From 6d5655e56aa7761f24d91c86a0fc4cb3dfd4736f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 15 Jan 2017 11:11:58 +0100 Subject: [PATCH] Progress on AI_CAS_ZONE and AI_PATROL_ZONE rework. --- Moose Development/Moose/AI/AI_CAS.lua | 425 +- Moose Development/Moose/AI/AI_Patrol.lua | 461 +- Moose Development/Moose/Core/Fsm.lua | 15 +- .../Moose/Core/ScheduleDispatcher.lua | 4 +- Moose Development/Moose/Core/Scheduler.lua | 2 +- .../Moose/Wrapper/Controllable.lua | 24 +- .../l10n/DEFAULT/Moose.lua | 30591 +--------------- Moose Mission Setup/Moose.lua | 30591 +--------------- .../AIB-001 - Spawned AI.miz | Bin 219487 -> 30747 bytes .../AIB-002 - Patrol AI.miz | Bin 219146 -> 31713 bytes ...-003 - Two coalitions InitCleanUp test.miz | Bin 226922 -> 38182 bytes .../AIB-004 - Respawn Test when Destroyed.miz | Bin 220915 -> 32175 bytes ...IB-005 - Patrol AI and Randomize Zones.miz | Bin 223147 -> 34407 bytes .../AIB-006 - Declutter AI at Airbases.miz | Bin 224204 -> 35464 bytes .../CAS-001 - CAS in a ZONE.lua | 23 +- .../CAS-001 - CAS in a ZONE.miz | Bin 219714 -> 32278 bytes .../CAS-001 - Manual Test.miz | Bin 207058 -> 18318 bytes docs/Presentations/AI_PATROL.pptx | Bin 0 -> 6222464 bytes docs/Presentations/MOOSE.pptx | Bin 5515670 -> 5515670 bytes 19 files changed, 536 insertions(+), 61600 deletions(-) create mode 100644 docs/Presentations/AI_PATROL.pptx diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 073ad1974..91996143a 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -95,177 +95,114 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude -- Inherits from BASE local self = BASE:Inherit( self, AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) ) -- #AI_CAS_ZONE - self.PatrolZone = PatrolZone - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed - self.EngageZone = EngageZone + self.Accomplished = false - do self:AddTransition( { "Patrol", "Route", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - --- OnLeave State Transition for Holding. - -- @function [parent=#AI_CAS_ZONE] OnLeaveHolding - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnBeforeEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnAfterEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Engage. - -- @function [parent=#AI_CAS_ZONE] Engage - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Engage - -- @function [parent=#AI_CAS_ZONE] __Engage - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - - do self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnBeforeFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnAfterFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean - - --- Embedded Event Trigger for Fired. - -- @function [parent=#AI_CAS_ZONE] Fired - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Fired - -- @function [parent=#AI_CAS_ZONE] __Fired - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - do self:AddTransition( "Engaging", "Destroy", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnBeforeDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnAfterDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Destroy. - -- @function [parent=#AI_CAS_ZONE] Destroy - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Destroy - -- @function [parent=#AI_CAS_ZONE] __Destroy - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - -do self:AddTransition( "Engaging", "Abort", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_CAS_ZONE] OnBeforeEngage -- @param #AI_CAS_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol + + --- OnAfter Transition Handler for Event Engage. + -- @function [parent=#AI_CAS_ZONE] OnAfterEngage -- @param #AI_CAS_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - - --- OnBefore State Transition for Abort. + + --- Synchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAS_ZONE] Engage + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAS_ZONE] __Engage + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging +-- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Engaging. +-- @function [parent=#AI_CAS_ZONE] OnEnterEngaging +-- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_CAS_ZONE] OnBeforeFired + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Fired. + -- @function [parent=#AI_CAS_ZONE] OnAfterFired + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAS_ZONE] Fired + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAS_ZONE] __Fired + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] OnBeforeDestroy + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] OnAfterDestroy + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] Destroy + -- @param #AI_CAS_ZONE self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAS_ZONE] __Destroy + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + + --- OnBefore Transition Handler for Event Abort. -- @function [parent=#AI_CAS_ZONE] OnBeforeAbort -- @param #AI_CAS_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. @@ -273,73 +210,51 @@ do self:AddTransition( "Engaging", "Abort", "Patrol" ) -- FSM_CONTROLLABLE Trans -- @param #string Event The Event string. -- @param #string To The To State string. -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Abort. + + --- OnAfter Transition Handler for Event Abort. -- @function [parent=#AI_CAS_ZONE] OnAfterAbort -- @param #AI_CAS_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - - --- Embedded Event Trigger for Abort. + + --- Synchronous Event Trigger for Event Abort. -- @function [parent=#AI_CAS_ZONE] Abort -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Abort + + --- Asynchronous Event Trigger for Event Abort. -- @function [parent=#AI_CAS_ZONE] __Abort -- @param #AI_CAS_ZONE self -- @param #number Delay The delay in seconds. -end -- AI_CAS_ZONE + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - do self:AddTransition( "Engaging", "Completed", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] OnBeforeAccomplish + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. + --- OnAfter Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] OnAfterAccomplish + -- @param #AI_CAS_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. - --- OnBefore State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnBeforeCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. + --- Synchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] Accomplish + -- @param #AI_CAS_ZONE self - --- OnAfter State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnAfterCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Completed. - -- @function [parent=#AI_CAS_ZONE] Completed - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Completed - -- @function [parent=#AI_CAS_ZONE] __Completed - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAS_ZONE] __Accomplish + -- @param #AI_CAS_ZONE self + -- @param #number Delay The delay in seconds. return self end @@ -354,15 +269,14 @@ end function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To ) - if Controllable:IsAlive() then - self:__Route( 1 ) - end - + self:Route() + self:__Status( 30 ) -- Check status status every 30 seconds. + self:__Detect( 30, self.EngageZone ) -- Detect for new targets every 30 seconds in the EngageZone. + self:EventOnDead( self.OnDead ) Controllable:OptionROEHoldFire() Controllable:OptionROTVertical() - end --- @param Wrapper.Controllable#CONTROLLABLE AIControllable @@ -373,6 +287,18 @@ function _NewEngageRoute( AIControllable ) EngageZone:__Engage( 1 ) end +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onbeforeEngage( Controllable, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + --- @param #AI_CAS_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. @@ -383,7 +309,27 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) if Controllable:IsAlive() then + self:Detect( self.EngageZone ) + local EngageRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToEngageZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + POINT_VEC3.RoutePointAltType.BARO, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToEngageZoneSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = CurrentRoutePoint + if self.Controllable:IsNotInZone( self.EngageZone ) then @@ -435,7 +381,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) true ) - ToTargetPointVec3:SmokeRed() + ToTargetPointVec3:SmokeBlue() EngageRoute[#EngageRoute+1] = ToTargetRoutePoint @@ -445,21 +391,16 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) local AttackTasks = {} - local DetectedTargets = Controllable:GetDetectedTargets() - for TargetID, Target in pairs( DetectedTargets ) do - local TargetObject = Target.object - self:T( TargetObject ) - if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then - - local TargetUnit = UNIT:Find( TargetObject ) - local TargetUnitName = TargetUnit:GetName() - - if TargetUnit:IsInZone( self.EngageZone ) then - self:E( {"Engaging ", TargetUnit } ) - --local EngageTask = Controllable:EnRouteTaskEngageUnit( TargetUnit, 1 ) - AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( TargetUnit ) + for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( DetectedUnit ) + if DetectedUnit:IsAlive() then + if DetectedUnit:IsInZone( self.EngageZone ) then + self:E( {"Engaging ", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) end - + else + self.DetectedUnits[DetectedUnit] = nil end end @@ -474,7 +415,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) + self.Controllable:WayPointExecute( 1, 2 ) end end @@ -483,11 +424,35 @@ end -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To ) +-- @param Core.Event#EVENTDATA EventData +function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) + if EventData.IniUnit then + self.DetectedUnits[EventData.IniUnit] = nil + end + Controllable:MessageToAll( "Destroyed a target", 15 , "Destroyed!" ) end +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterRTB( Controllable, From, Event, To, EventData ) + self.CheckStatus = false +end + +--- @param #AI_CAS_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_CAS_ZONE:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self.DetectUnits = false +end + --- @param #AI_CAS_ZONE self -- @param Core.Event#EVENTDATA EventData function AI_CAS_ZONE:OnDead( EventData ) diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 8d3ccf4e3..f7088ee72 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -140,6 +140,7 @@ -- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. -- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. -- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @field Functional.Spawn#SPAWN CoordTest -- @extends Core.Fsm#FSM_CONTROLLABLE AI_PATROLZONE = { ClassName = "AI_PATROLZONE", @@ -166,204 +167,194 @@ function AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitu local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_CONTROLLABLE - self.PatrolZone = PatrolZone + self.PatrolZone = PatrolZone self.PatrolFloorAltitude = PatrolFloorAltitude self.PatrolCeilingAltitude = PatrolCeilingAltitude self.PatrolMinSpeed = PatrolMinSpeed self.PatrolMaxSpeed = PatrolMaxSpeed + self.DetectUnits = true + self.CheckStatus = true + + self.DetectedUnits = {} -- This table contains the targets detected during patrol. + self.PatrolFuelTresholdPercentage = 0.2 - - self:SetStartState( "None" ) + self:SetStartState( "None" ) -do self:AddTransition( "*", "Start", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. + self:AddTransition( "None", "Start", "Patrolling" ) - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. +--- OnBefore Transition Handler for Event Start. +-- @function [parent=#AI_PATROLZONE] OnBeforeStart +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. +--- OnAfter Transition Handler for Event Start. +-- @function [parent=#AI_PATROLZONE] OnAfterStart +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. - --- OnBefore State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnBeforeStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. +--- Synchronous Event Trigger for Event Start. +-- @function [parent=#AI_PATROLZONE] Start +-- @param #AI_PATROLZONE self - --- OnAfter State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnAfterStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. +--- Asynchronous Event Trigger for Event Start. +-- @function [parent=#AI_PATROLZONE] __Start +-- @param #AI_PATROLZONE self +-- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Patrolling. +-- @function [parent=#AI_PATROLZONE] OnLeavePatrolling +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Patrolling. +-- @function [parent=#AI_PATROLZONE] OnEnterPatrolling +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Patrolling", "Route", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. + +--- OnBefore Transition Handler for Event Route. +-- @function [parent=#AI_PATROLZONE] OnBeforeRoute +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Route. +-- @function [parent=#AI_PATROLZONE] OnAfterRoute +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. - --- Embedded Event Trigger for Start. - -- @function [parent=#AI_PATROLZONE] Start - -- @param #AI_PATROLZONE self +--- Synchronous Event Trigger for Event Route. +-- @function [parent=#AI_PATROLZONE] Route +-- @param #AI_PATROLZONE self - --- Delayed Event Trigger for Start - -- @function [parent=#AI_PATROLZONE] __Start - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. +--- Asynchronous Event Trigger for Event Route. +-- @function [parent=#AI_PATROLZONE] __Route +-- @param #AI_PATROLZONE self +-- @param #number Delay The delay in seconds. -end -- AI_PATROLZONE + self:AddTransition( "*", "Status", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. -do self:AddTransition( "*", "Route", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. +--- OnBefore Transition Handler for Event Status. +-- @function [parent=#AI_PATROLZONE] OnBeforeStatus +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. +--- OnAfter Transition Handler for Event Status. +-- @function [parent=#AI_PATROLZONE] OnAfterStatus +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. - --- OnBefore State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnBeforeRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. +--- Synchronous Event Trigger for Event Status. +-- @function [parent=#AI_PATROLZONE] Status +-- @param #AI_PATROLZONE self - --- OnAfter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnAfterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. +--- Asynchronous Event Trigger for Event Status. +-- @function [parent=#AI_PATROLZONE] __Status +-- @param #AI_PATROLZONE self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Detect", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. + +--- OnBefore Transition Handler for Event Detect. +-- @function [parent=#AI_PATROLZONE] OnBeforeDetect +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnAfter Transition Handler for Event Detect. +-- @function [parent=#AI_PATROLZONE] OnAfterDetect +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. - --- Embedded Event Trigger for Route. - -- @function [parent=#AI_PATROLZONE] Route - -- @param #AI_PATROLZONE self +--- Synchronous Event Trigger for Event Detect. +-- @function [parent=#AI_PATROLZONE] Detect +-- @param #AI_PATROLZONE self - --- Delayed Event Trigger for Route - -- @function [parent=#AI_PATROLZONE] __Route - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. +--- Asynchronous Event Trigger for Event Detect. +-- @function [parent=#AI_PATROLZONE] __Detect +-- @param #AI_PATROLZONE self +-- @param #number Delay The delay in seconds. -end -- AI_PATROLZONE + self:AddTransition( "*", "RTB", "RTB" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. -do self:AddTransition( "*", "Patrol", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. +--- OnBefore Transition Handler for Event RTB. +-- @function [parent=#AI_PATROLZONE] OnBeforeRTB +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnEnterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. +--- OnAfter Transition Handler for Event RTB. +-- @function [parent=#AI_PATROLZONE] OnAfterRTB +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. - --- OnBefore State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnBeforePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. +--- Synchronous Event Trigger for Event RTB. +-- @function [parent=#AI_PATROLZONE] RTB +-- @param #AI_PATROLZONE self - --- OnAfter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnAfterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Patrol. - -- @function [parent=#AI_PATROLZONE] Patrol - -- @param #AI_PATROLZONE self +--- Asynchronous Event Trigger for Event RTB. +-- @function [parent=#AI_PATROLZONE] __RTB +-- @param #AI_PATROLZONE self +-- @param #number Delay The delay in seconds. - --- Delayed Event Trigger for Patrol - -- @function [parent=#AI_PATROLZONE] __Patrol - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. +--- OnLeave Transition Handler for State Returning. +-- @function [parent=#AI_PATROLZONE] OnLeaveReturning +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. -end -- AI_PATROLZONE - -do self:AddTransition( "Patrol", "RTB", "RTB" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnEnterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnBeforeRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnAfterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for RTB. - -- @function [parent=#AI_PATROLZONE] RTB - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for RTB - -- @function [parent=#AI_PATROLZONE] __RTB - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE +--- OnEnter Transition Handler for State Returning. +-- @function [parent=#AI_PATROLZONE] OnEnterReturning +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. return self end @@ -399,14 +390,6 @@ end ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewPatrolRoute( AIControllable ) - - AIControllable:T( "NewPatrolRoute" ) - local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolCore.Zone#AI_PATROLZONE - PatrolZone:__Route( 1 ) -end - @@ -430,29 +413,102 @@ end --- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. -- @param #AI_PATROLZONE self -- @return #AI_PATROLZONE self -function AI_PATROLZONE:onenterRoute() +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_PATROLZONE:onafterStart( Controllable, From, Event, To ) + self:F2() + + self:Route() -- Route to the patrol point. + self:__Status( 30 ) -- Check status status every 30 seconds. + self:__Detect( 30 ) -- Detect for new targets every 30 seconds. + + Controllable:OptionROEHoldFire() + Controllable:OptionROTVertical() + +end + + +--- @param #AI_PATROLZONE self +--- @param Wrapper.Controllable#CONTROLLABLE Controllable +function AI_PATROLZONE:onbeforeDetect( Controllable, From, Event, To, DetectZone ) + + return self.DetectUnits +end + +--- @param #AI_PATROLZONE self +--- @param Wrapper.Controllable#CONTROLLABLE Controllable +function AI_PATROLZONE:onafterDetect( Controllable, From, Event, To, DetectZone ) + + local DetectedTargets = Controllable:GetDetectedTargets() + for TargetID, Target in pairs( DetectedTargets ) do + local TargetObject = Target.object + self:T( TargetObject ) + if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then + + local TargetUnit = UNIT:Find( TargetObject ) + local TargetUnitName = TargetUnit:GetName() + + if DetectZone then + if TargetUnit:IsInZone( DetectZone ) then + self:T( {"Detected ", TargetUnit } ) + self.DetectedUnits[TargetUnit] = TargetUnit + end + else + self.DetectedUnits[TargetUnit] = TargetUnit + end + end + end + +end + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +function _NewPatrolRoute( AIControllable ) + + AIControllable:T( "NewPatrolRoute" ) + local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolCore.Zone#AI_PATROLZONE + PatrolZone:Route() +end + + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_PATROLZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_PATROLZONE:onafterRoute( Controllable, From, Event, To ) self:F2() + -- When RTB, don't allow anymore the routing. + if From == "RTB" then + return + end + local PatrolRoute = {} if self.Controllable:IsAlive() then --- Determine if the AIControllable is within the PatrolZone. -- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point. --- --- Calculate the current route point. --- local CurrentVec2 = self.Controllable:GetVec2() --- local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() --- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) --- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( --- POINT_VEC3.RoutePointAltType.BARO, --- POINT_VEC3.RoutePointType.TurningPoint, --- POINT_VEC3.RoutePointAction.TurningPoint, --- ToPatrolZoneSpeed, --- true --- ) --- --- PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToPatrolZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + POINT_VEC3.RoutePointAltType.BARO, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToPatrolZoneSpeed, + true + ) + + PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint self:T2( PatrolRoute ) @@ -505,7 +561,9 @@ function AI_PATROLZONE:onenterRoute() true ) - --ToTargetPointVec3:SmokeRed() + --self.CoordTest:SpawnFromVec3( ToTargetPointVec3:GetVec3() ) + + ToTargetPointVec3:SmokeRed() PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint @@ -517,16 +575,19 @@ function AI_PATROLZONE:onenterRoute() self.Controllable:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" ) --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) - - self:__Patrol( 30 ) + self.Controllable:WayPointExecute( 1, 2 ) end - + end +--- @param #AI_PATROLZONE self +function AI_PATROLZONE:onbeforeStatus() + + return self.CheckStatus +end --- @param #AI_PATROLZONE self -function AI_PATROLZONE:onenterPatrol() +function AI_PATROLZONE:onafterStatus() self:F2() if self.Controllable and self.Controllable:IsAlive() then @@ -542,8 +603,10 @@ function AI_PATROLZONE:onenterPatrol() self:RTB() else - self:__Patrol( 30 ) -- Execute the Patrol event after 30 seconds. + self:__Status( 30 ) -- Execute the Patrol event after 30 seconds. end + + self:__Detect( 30 ) -- Detect for new targets every 30 seconds. end end diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 2d1948aee..d1967153e 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -535,14 +535,17 @@ do -- FSM function FSM._handler( self, EventName, ... ) - self:E( { EventName, ... } ) - local Can, to = self:can( EventName ) - self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) + + if to == "*" then + to = self.current + end if Can then local from = self.current local params = { from, EventName, to, ... } + + self:E( "FSM Transition:" .. self.current .. " --> " .. EventName .. " --> " .. to ) if self:_call_handler("onbefore" .. EventName, params) == false or self:_call_handler("OnBefore" .. EventName, params) == false @@ -592,6 +595,9 @@ do -- FSM self:_call_handler("onstatechange", params) end + else + self:E( "Cannot execute transition." ) + self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) end return nil @@ -667,7 +673,6 @@ do -- FSM end function FSM:can(e) - self:E( { e, self.Events, self.Events[e] } ) local Event = self.Events[e] self:F3( { self.current, Event } ) local To = Event and Event.map[self.current] or Event.map['*'] @@ -736,7 +741,7 @@ do -- FSM_CONTROLLABLE end if self[handler] then - self:E( "Calling " .. handler ) + self:F3( "Calling " .. handler ) return xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) --return self[handler]( self, self.Controllable, unpack( params ) ) end diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index fc2933cde..277fb7b8e 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -68,10 +68,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr if Scheduler.MasterObject then self.ObjectSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) + self:F3( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) else self.PersistentSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) + self:F3( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) end self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 39604c2b7..2b68e54bd 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -102,7 +102,7 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID end - self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) + self:F3( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) self.SchedulerObject = SchedulerObject local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index b2a32f951..cf445b5f3 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -305,6 +305,10 @@ function CONTROLLABLE:TaskCombo( DCSTasks ) tasks = DCSTasks } } + + for TaskID, Task in ipairs( DCSTasks ) do + self:E( Task ) + end self:T3( { DCSTaskCombo } ) return DCSTaskCombo @@ -490,22 +494,24 @@ function CONTROLLABLE:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, Atta -- } local DCSTask - DCSTask = { id = 'AttackUnit', + DCSTask = { + id = 'AttackUnit', params = { - altitudeEnabled = false, + altitudeEnabled = true, unitId = AttackUnit:GetID(), attackQtyLimit = AttackQtyLimit or false, - attackQty = AttackQty or 1, + attackQty = AttackQty or 2, expend = WeaponExpend or "Auto", altitude = 2000, - directionEnabled = false, - groupAttack = false, - weaponType = WeaponType or 1073741822, + directionEnabled = true, + groupAttack = true, + --weaponType = WeaponType or 1073741822, direction = Direction or 0, - }, - }, + } + } - self:E( { DCSTask } ) + self:E( DCSTask ) + return DCSTask end diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua index 1e630b10b..57003e86e 100644 --- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua +++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua @@ -1,30588 +1,31 @@ -env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170113_2007' ) +env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) +env.info( 'Moose Generation Timestamp: 20170113_2015' ) + local base = _G Include = {} -Include.Files = {} + Include.File = function( IncludeFile ) -end - ---- Various routines --- @module routines --- @author Flightcontrol - -env.setErrorMessageBoxEnabled(false) - ---- Extract of MIST functions. --- @author Grimes - -routines = {} - - --- don't change these -routines.majorVersion = 3 -routines.minorVersion = 3 -routines.build = 22 - ------------------------------------------------------------------------------------------------------------------ - ----------------------------------------------------------------------------------------------- --- Utils- conversion, Lua utils, etc. -routines.utils = {} - ---from http://lua-users.org/wiki/CopyTable -routines.utils.deepCopy = function(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - local objectreturn = _copy(object) - return objectreturn -end - - --- porting in Slmod's serialize_slmod2 -routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - - lookup_table = {} - - local function _Serialize( tbl ) - - if type(tbl) == 'table' then --function only works for tables! - - if lookup_table[tbl] then - return lookup_table[object] - end - - local tbl_str = {} - - lookup_table[tbl] = tbl_str - - tbl_str[#tbl_str + 1] = '{' - - for ind,val in pairs(tbl) do -- serialize its fields - local ind_str = {} - if type(ind) == "number" then - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = tostring(ind) - ind_str[#ind_str + 1] = ']=' - else --must be a string - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) - ind_str[#ind_str + 1] = ']=' - end - - local val_str = {} - if ((type(val) == 'number') or (type(val) == 'boolean')) then - val_str[#val_str + 1] = tostring(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'string' then - val_str[#val_str + 1] = routines.utils.basicSerialize(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'nil' then -- won't ever happen, right? - val_str[#val_str + 1] = 'nil,' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'table' then - if ind == "__index" then - -- tbl_str[#tbl_str + 1] = "__index" - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - - val_str[#val_str + 1] = _Serialize(val) - val_str[#val_str + 1] = ',' --I think this is right, I just added it - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - end - elseif type(val) == 'function' then - -- tbl_str[#tbl_str + 1] = "function " .. tostring(ind) - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else --- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) --- env.info( debug.traceback() ) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) + if not Include.Files[ IncludeFile ] then + Include.Files[IncludeFile] = IncludeFile + env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath ) + local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) ) + if f == nil then + error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) else - return tostring(tbl) + env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) + return f() end end - - local objectreturn = _Serialize(tbl) - return objectreturn end ---porting in Slmod's "safestring" basic serialize -routines.utils.basicSerialize = function(s) - if s == nil then - return "\"\"" - else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) - return s - end - end -end - - -routines.utils.toDegree = function(angle) - return angle*180/math.pi -end - -routines.utils.toRadian = function(angle) - return angle*math.pi/180 -end - -routines.utils.metersToNM = function(meters) - return meters/1852 -end - -routines.utils.metersToFeet = function(meters) - return meters/0.3048 -end - -routines.utils.NMToMeters = function(NM) - return NM*1852 -end - -routines.utils.feetToMeters = function(feet) - return feet*0.3048 -end - -routines.utils.mpsToKnots = function(mps) - return mps*3600/1852 -end - -routines.utils.mpsToKmph = function(mps) - return mps*3.6 -end - -routines.utils.knotsToMps = function(knots) - return knots*1852/3600 -end - -routines.utils.kmphToMps = function(kmph) - return kmph/3.6 -end - -function routines.utils.makeVec2(Vec3) - if Vec3.z then - return {x = Vec3.x, y = Vec3.z} - else - return {x = Vec3.x, y = Vec3.y} -- it was actually already vec2. - end -end - -function routines.utils.makeVec3(Vec2, y) - if not Vec2.z then - if not y then - y = 0 - end - return {x = Vec2.x, y = y, z = Vec2.y} - else - return {x = Vec2.x, y = Vec2.y, z = Vec2.z} -- it was already Vec3, actually. - end -end - -function routines.utils.makeVec3GL(Vec2, offset) - local adj = offset or 0 - - if not Vec2.z then - return {x = Vec2.x, y = (land.getHeight(Vec2) + adj), z = Vec2.y} - else - return {x = Vec2.x, y = (land.getHeight({x = Vec2.x, y = Vec2.z}) + adj), z = Vec2.z} - end -end - -routines.utils.zoneToVec3 = function(zone) - local new = {} - if type(zone) == 'table' and zone.point then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - elseif type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - if zone then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - end - end -end - --- gets heading-error corrected direction from point along vector vec. -function routines.utils.getDir(vec, point) - local dir = math.atan2(vec.z, vec.x) - dir = dir + routines.getNorthCorrection(point) - if dir < 0 then - dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi - end - return dir -end - --- gets distance in meters between two points (2 dimensional) -function routines.utils.get2DDist(point1, point2) - point1 = routines.utils.makeVec3(point1) - point2 = routines.utils.makeVec3(point2) - return routines.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) -end - --- gets distance in meters between two points (3 dimensional) -function routines.utils.get3DDist(point1, point2) - return routines.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) -end - - - - - ---3D Vector manipulation -routines.vec = {} - -routines.vec.add = function(vec1, vec2) - return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} -end - -routines.vec.sub = function(vec1, vec2) - return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} -end - -routines.vec.scalarMult = function(vec, mult) - return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} -end - -routines.vec.scalar_mult = routines.vec.scalarMult - -routines.vec.dp = function(vec1, vec2) - return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z -end - -routines.vec.cp = function(vec1, vec2) - return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} -end - -routines.vec.mag = function(vec) - return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 -end - -routines.vec.getUnitVec = function(vec) - local mag = routines.vec.mag(vec) - return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } -end - -routines.vec.rotateVec2 = function(vec2, theta) - return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} -end ---------------------------------------------------------------------------------------------------------------------------- - - - - --- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -routines.tostringMGRS = function(MGRS, acc) - if acc == 0 then - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph - else - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Easting/(10^(5-acc)), 0)) - .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Northing/(10^(5-acc)), 0)) - end -end - ---[[acc: -in DM: decimal point of minutes. -In DMS: decimal point of seconds. -position after the decimal of the least significant digit: -So: -42.32 - acc of 2. -]] -routines.tostringLL = function(lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = routines.utils.round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = routines.utils.round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - - else -- degrees, decimal minutes. - latMin = routines.utils.round(latMin, acc) - lonMin = routines.utils.round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end -end - ---[[ required: az - radian - required: dist - meters - optional: alt - meters (set to false or nil if you don't want to use it). - optional: metric - set true to get dist and alt in km and m. - precision will always be nearest degree and NM or km.]] -routines.tostringBR = function(az, dist, alt, metric) - az = routines.utils.round(routines.utils.toDegree(az), 0) - - if metric then - dist = routines.utils.round(dist/1000, 2) - else - dist = routines.utils.round(routines.utils.metersToNM(dist), 2) - end - - local s = string.format('%03d', az) .. ' for ' .. dist - - if alt then - if metric then - s = s .. ' at ' .. routines.utils.round(alt, 0) - else - s = s .. ' at ' .. routines.utils.round(routines.utils.metersToFeet(alt), 0) - end - end - return s -end - -routines.getNorthCorrection = function(point) --gets the correction needed for true north - if not point.z then --Vec2; convert to Vec3 - point.z = point.y - point.y = 0 - end - local lat, lon = coord.LOtoLL(point) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2(north_posit.z - point.z, north_posit.x - point.x) -end - - -do - local idNum = 0 - - --Simplified event handler - routines.addEventHandler = function(f) --id is optional! - local handler = {} - idNum = idNum + 1 - handler.id = idNum - handler.f = f - handler.onEvent = function(self, event) - self.f(event) - end - world.addEventHandler(handler) - end - - routines.removeEventHandler = function(id) - for key, handler in pairs(world.eventHandlers) do - if handler.id and handler.id == id then - world.eventHandlers[key] = nil - return true - end - end - return false - end -end - --- need to return a Vec3 or Vec2? -function routines.getRandPointInCircle(point, radius, innerRadius) - local theta = 2*math.pi*math.random() - local rad = math.random() + math.random() - if rad > 1 then - rad = 2 - rad - end - - local radMult - if innerRadius and innerRadius <= radius then - radMult = (radius - innerRadius)*rad + innerRadius - else - radMult = radius*rad - end - - if not point.z then --might as well work with vec2/3 - point.z = point.y - end - - local rndCoord - if radius > 0 then - rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} - else - rndCoord = {x = point.x, y = point.z} - end - return rndCoord -end - -routines.goRoute = function(group, path) - local misTask = { - id = 'Mission', - params = { - route = { - points = routines.utils.deepCopy(path), - }, - }, - } - if type(group) == 'string' then - group = Group.getByName(group) - end - local groupCon = group:getController() - if groupCon then - groupCon:setTask(misTask) - return true - end - - Controller.setTask(groupCon, misTask) - return false -end - - --- Useful atomic functions from mist, ported. - -routines.ground = {} -routines.fixedWing = {} -routines.heli = {} - -routines.ground.buildWP = function(point, overRideForm, overRideSpeed) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - local form, speed - - if point.speed and not overRideSpeed then - wp.speed = point.speed - elseif type(overRideSpeed) == 'number' then - wp.speed = overRideSpeed - else - wp.speed = routines.utils.kmphToMps(20) - end - - if point.form and not overRideForm then - form = point.form - else - form = overRideForm - end - - if not form then - wp.action = 'Cone' - else - form = string.lower(form) - if form == 'off_road' or form == 'off road' then - wp.action = 'Off Road' - elseif form == 'on_road' or form == 'on road' then - wp.action = 'On Road' - elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then - wp.action = 'Rank' - elseif form == 'cone' then - wp.action = 'Cone' - elseif form == 'diamond' then - wp.action = 'Diamond' - elseif form == 'vee' then - wp.action = 'Vee' - elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then - wp.action = 'EchelonL' - elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then - wp.action = 'EchelonR' - else - wp.action = 'Cone' -- if nothing matched - end - end - - wp.type = 'Turning Point' - - return wp - -end - -routines.fixedWing.buildWP = function(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 2000 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = routines.utils.kmphToMps(500) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp -end - -routines.heli.buildWP = function(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 500 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = routines.utils.kmphToMps(200) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp -end - -routines.groupToRandomPoint = function(vars) - local group = vars.group --Required - local point = vars.point --required - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - local form = vars.form or 'Cone' - local heading = vars.heading or math.random()*2*math.pi - local headingDegrees = vars.headingDegrees - local speed = vars.speed or routines.utils.kmphToMps(20) - - - local useRoads - if not vars.disableRoads then - useRoads = true - else - useRoads = false - end - - local path = {} - - if headingDegrees then - heading = headingDegrees*math.pi/180 - end - - if heading >= 2*math.pi then - heading = heading - 2*math.pi - end - - local rndCoord = routines.getRandPointInCircle(point, radius, innerRadius) - - local offset = {} - local posStart = routines.getLeadPos(group) - - offset.x = routines.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) - offset.z = routines.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) - path[#path + 1] = routines.ground.buildWP(posStart, form, speed) - - - if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then - path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed) - path[#path + 1] = routines.ground.buildWP(posStart, 'on_road', speed) - path[#path + 1] = routines.ground.buildWP(offset, 'on_road', speed) - else - path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed) - end - - path[#path + 1] = routines.ground.buildWP(offset, form, speed) - path[#path + 1] = routines.ground.buildWP(rndCoord, form, speed) - - routines.goRoute(group, path) - - return -end - -routines.groupRandomDistSelf = function(gpData, dist, form, heading, speed) - local pos = routines.getLeadPos(gpData) - local fakeZone = {} - fakeZone.radius = dist or math.random(300, 1000) - fakeZone.point = {x = pos.x, y, pos.y, z = pos.z} - routines.groupToRandomZone(gpData, fakeZone, form, heading, speed) - - return -end - -routines.groupToRandomZone = function(gpData, zone, form, heading, speed) - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end - - if speed then - speed = routines.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.radius = zone.radius - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.point = routines.utils.zoneToVec3(zone) - - routines.groupToRandomPoint(vars) - - return -end - -routines.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types - if coord.z then - coord.y = coord.z - end - local typeConverted = {} - - if type(terrainTypes) == 'string' then -- if its a string it does this check - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then - table.insert(typeConverted, constId) - end - end - elseif type(terrainTypes) == 'table' then -- if its a table it does this check - for typeId, typeData in pairs(terrainTypes) do - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then - table.insert(typeConverted, constId) - end - end - end - end - for validIndex, validData in pairs(typeConverted) do - if land.getSurfaceType(coord) == land.SurfaceType[validData] then - return true - end - end - return false -end - -routines.groupToPoint = function(gpData, point, form, heading, speed, useRoads) - if type(point) == 'string' then - point = trigger.misc.getZone(point) - end - if speed then - speed = routines.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.disableRoads = useRoads - vars.point = routines.utils.zoneToVec3(point) - routines.groupToRandomPoint(vars) - - return -end - - -routines.getLeadPos = function(group) - if type(group) == 'string' then -- group name - group = Group.getByName(group) - end - - local units = group:getUnits() - - local leader = units[1] - if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then. - local lowestInd = math.huge - for ind, unit in pairs(units) do - if ind < lowestInd then - lowestInd = ind - leader = unit - end - end - end - if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... - return leader:getPosition().p - end -end - ---[[ vars for routines.getMGRSString: -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -]] -routines.getMGRSString = function(vars) - local units = vars.units - local acc = vars.acc or 5 - local avgPos = routines.getAvgPos(units) - if avgPos then - return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) - end -end - ---[[ vars for routines.getLLString -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. - - -]] -routines.getLLString = function(vars) - local units = vars.units - local acc = vars.acc or 3 - local DMS = vars.DMS - local avgPos = routines.getAvgPos(units) - if avgPos then - local lat, lon = coord.LOtoLL(avgPos) - return routines.tostringLL(lat, lon, acc, DMS) - end -end - ---[[ -vars.zone - table of a zone name. -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -]] -routines.getBRStringZone = function(vars) - local zone = trigger.misc.getZone( vars.zone ) - local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - if zone then - local vec = {x = zone.point.x - ref.x, y = zone.point.y - ref.y, z = zone.point.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(zone.point, ref) - if alt then - alt = zone.y - end - return routines.tostringBR(dir, dist, alt, metric) - else - env.info( 'routines.getBRStringZone: error: zone is nil' ) - end -end - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -]] -routines.getBRString = function(vars) - local units = vars.units - local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - local avgPos = routines.getAvgPos(units) - if avgPos then - local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(avgPos, ref) - if alt then - alt = avgPos.y - end - return routines.tostringBR(dir, dist, alt, metric) - end -end - - --- Returns the Vec3 coordinates of the average position of the concentration of units most in the heading direction. ---[[ vars for routines.getLeadingPos: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -]] -routines.getLeadingPos = function(vars) - local units = vars.units - local heading = vars.heading - local radius = vars.radius - if vars.headingDegrees then - heading = routines.utils.toRadian(vars.headingDegrees) - end - - local unitPosTbl = {} - for i = 1, #units do - local unit = Unit.getByName(units[i]) - if unit and unit:isExist() then - unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p - end - end - if #unitPosTbl > 0 then -- one more more units found. - -- first, find the unit most in the heading direction - local maxPos = -math.huge - - local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = - for i = 1, #unitPosTbl do - local rotatedVec2 = routines.vec.rotateVec2(routines.utils.makeVec2(unitPosTbl[i]), heading) - if (not maxPos) or maxPos < rotatedVec2.x then - maxPos = rotatedVec2.x - maxPosInd = i - end - end - - --now, get all the units around this unit... - local avgPos - if radius then - local maxUnitPos = unitPosTbl[maxPosInd] - local avgx, avgy, avgz, totNum = 0, 0, 0, 0 - for i = 1, #unitPosTbl do - if routines.utils.get2DDist(maxUnitPos, unitPosTbl[i]) <= radius then - avgx = avgx + unitPosTbl[i].x - avgy = avgy + unitPosTbl[i].y - avgz = avgz + unitPosTbl[i].z - totNum = totNum + 1 - end - end - avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} - else - avgPos = unitPosTbl[maxPosInd] - end - - return avgPos - end -end - - ---[[ vars for routines.getLeadingMGRSString: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number, 0 to 5. -]] -routines.getLeadingMGRSString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local acc = vars.acc or 5 - return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) - end -end - ---[[ vars for routines.getLeadingLLString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. -]] -routines.getLeadingLLString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local acc = vars.acc or 3 - local DMS = vars.DMS - local lat, lon = coord.LOtoLL(pos) - return routines.tostringLL(lat, lon, acc, DMS) - end -end - - - ---[[ vars for routines.getLeadingBRString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.metric - boolean, if true, use km instead of NM. -vars.alt - boolean, if true, include altitude. -vars.ref - vec3/vec2 reference point. -]] -routines.getLeadingBRString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local ref = vars.ref - local alt = vars.alt - local metric = vars.metric - - local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(pos, ref) - if alt then - alt = pos.y - end - return routines.tostringBR(dir, dist, alt, metric) - end -end - ---[[ vars for routines.message.add - vars.text = 'Hello World' - vars.displayTime = 20 - vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} - -]] - ---[[ vars for routines.msgMGRS -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] -routines.msgMGRS = function(vars) - local units = vars.units - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getMGRSString{units = units, acc = acc} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } -end - ---[[ vars for routines.msgLL -vars.units - table of unit names (NOT unitNameTable- maybe this should change) (Yes). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] -routines.msgLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLLString{units = units, acc = acc, DMS = DMS} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString - local alt = vars.alt - local metric = vars.metric - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getBRString{units = units, ref = ref, alt = alt, metric = metric} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - - --------------------------------------------------------------------------------------------- --- basically, just sub-types of routines.msgBR... saves folks the work of getting the ref point. ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - string red, blue -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgBullseye = function(vars) - if string.lower(vars.ref) == 'red' then - vars.ref = routines.DBs.missionData.bullseye.red - routines.msgBR(vars) - elseif string.lower(vars.ref) == 'blue' then - vars.ref = routines.DBs.missionData.bullseye.blue - routines.msgBR(vars) - end -end - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - unit name of reference point -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - -routines.msgBRA = function(vars) - if Unit.getByName(vars.ref) then - vars.ref = Unit.getByName(vars.ref):getPosition().p - if not vars.alt then - vars.alt = true - end - routines.msgBR(vars) - end -end --------------------------------------------------------------------------------------------- - ---[[ vars for routines.msgLeadingMGRS: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number, 0 to 5. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingMGRS = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - -end ---[[ vars for routines.msgLeadingLL: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. (optional) -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - ---[[ -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.metric - boolean, if true, use km instead of NM. (optional) -vars.alt - boolean, if true, include altitude. (optional) -vars.ref - vec3/vec2 reference point. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local metric = vars.metric - local alt = vars.alt - local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } -end - - -function spairs(t, order) - -- collect the keys - local keys = {} - for k in pairs(t) do keys[#keys+1] = k end - - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(t, a, b) end) - else - table.sort(keys) - end - - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keys[i], t[keys[i]] - end - end -end - - -function routines.IsPartOfGroupInZones( CargoGroup, LandingZones ) ---trace.f() - - local CurrentZoneID = nil - - if CargoGroup then - local CargoUnits = CargoGroup:getUnits() - for CargoUnitID, CargoUnit in pairs( CargoUnits ) do - if CargoUnit and CargoUnit:getLife() >= 1.0 then - CurrentZoneID = routines.IsUnitInZones( CargoUnit, LandingZones ) - if CurrentZoneID then - break - end - end - end - end - ---trace.r( "", "", { CurrentZoneID } ) - return CurrentZoneID -end - - - -function routines.IsUnitInZones( TransportUnit, LandingZones ) ---trace.f("", "routines.IsUnitInZones" ) - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - if TransportUnit then - local TransportUnitPos = TransportUnit:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = 1 - end - end - if TransportZoneResult then - --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) - else - --trace.i( "routines", "TransportZone:nil logic" ) - end - return TransportZoneResult - else - --trace.i( "routines", "TransportZone:nil hard" ) - return nil - end -end - -function routines.IsUnitNearZonesRadius( TransportUnit, LandingZones, ZoneRadius ) ---trace.f("", "routines.IsUnitInZones" ) - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - if TransportUnit then - local TransportUnitPos = TransportUnit:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then - TransportZoneResult = 1 - end - end - if TransportZoneResult then - --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) - else - --trace.i( "routines", "TransportZone:nil logic" ) - end - return TransportZoneResult - else - --trace.i( "routines", "TransportZone:nil hard" ) - return nil - end -end - - -function routines.IsStaticInZones( TransportStatic, LandingZones ) ---trace.f() - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - local TransportStaticPos = TransportStatic:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = 1 - end - end - ---trace.r( "", "", { TransportZoneResult } ) - return TransportZoneResult -end - - -function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius ) ---trace.f() - - local Valid = true - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - local CargoPos = CargoUnit:getPosition().p - local ReferenceP = ReferencePosition.p - - if (((CargoPos.x - ReferenceP.x)^2 + (CargoPos.z - ReferenceP.z)^2)^0.5 <= Radius) then - else - Valid = false - end - - return Valid -end - -function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius ) ---trace.f() - - local Valid = true - - Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid ) - - -- fill-up some local variables to support further calculations to determine location of units within the zone - local CargoUnits = CargoGroup:getUnits() - for CargoUnitId, CargoUnit in pairs( CargoUnits ) do - local CargoUnitPos = CargoUnit:getPosition().p --- env.info( 'routines.IsPartOfGroupInRadius: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z ) - local ReferenceP = ReferencePosition.p --- env.info( 'routines.IsPartOfGroupInRadius: ReferenceGroupPos.x = ' .. ReferenceGroupPos.x .. ' ReferenceGroupPos.z = ' .. ReferenceGroupPos.z ) - - if ((( CargoUnitPos.x - ReferenceP.x)^2 + (CargoUnitPos.z - ReferenceP.z)^2)^0.5 <= Radius) then - else - Valid = false - break - end - end - - return Valid -end - - -function routines.ValidateString( Variable, VariableName, Valid ) ---trace.f() - - if type( Variable ) == "string" then - if Variable == "" then - error( "routines.ValidateString: error: " .. VariableName .. " must be filled out!" ) - Valid = false - end - else - error( "routines.ValidateString: error: " .. VariableName .. " is not a string." ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateNumber( Variable, VariableName, Valid ) ---trace.f() - - if type( Variable ) == "number" then - else - error( "routines.ValidateNumber: error: " .. VariableName .. " is not a number." ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid - -end - -function routines.ValidateGroup( Variable, VariableName, Valid ) ---trace.f() - - if Variable == nil then - error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateZone( LandingZones, VariableName, Valid ) ---trace.f() - - if LandingZones == nil then - error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) - Valid = false - end - - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - if trigger.misc.getZone( LandingZoneName ) == nil then - error( "routines.ValidateGroup: error: Zone " .. LandingZoneName .. " does not exist!" ) - Valid = false - break - end - end - else - if trigger.misc.getZone( LandingZones ) == nil then - error( "routines.ValidateGroup: error: Zone " .. LandingZones .. " does not exist!" ) - Valid = false - end - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateEnumeration( Variable, VariableName, Enum, Valid ) ---trace.f() - - local ValidVariable = false - - for EnumId, EnumData in pairs( Enum ) do - if Variable == EnumData then - ValidVariable = true - break - end - end - - if ValidVariable then - else - error( 'TransportValidateEnum: " .. VariableName .. " is not a valid type.' .. Variable ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints but returns speed and formation type along with vec2 of point} - -- refactor to search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = _DATABASE.Templates.Groups[groupIdent].groupId - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - - for point_num, point in pairs(group_data.route.points) do - local routeData = {} - if not point.point then - routeData.x = point.x - routeData.y = point.y - else - routeData.point = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - routeData.form = point.action - routeData.speed = point.speed - routeData.alt = point.alt - routeData.alt_type = point.alt_type - routeData.airdromeId = point.airdromeId - routeData.helipadId = point.helipadId - routeData.type = point.type - routeData.action = point.action - if task then - routeData.task = point.task - end - points[point_num] = routeData - end - - return points - end - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do -end - -routines.ground.patrolRoute = function(vars) - - - local tempRoute = {} - local useRoute = {} - local gpData = vars.gpData - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - local useGroupRoute - if not vars.useGroupRoute then - useGroupRoute = vars.gpData - else - useGroupRoute = vars.useGroupRoute - end - local routeProvided = false - if not vars.route then - if useGroupRoute then - tempRoute = routines.getGroupRoute(useGroupRoute) - end - else - useRoute = vars.route - local posStart = routines.getLeadPos(gpData) - useRoute[1] = routines.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) - routeProvided = true - end - - - local overRideSpeed = vars.speed or 'default' - local pType = vars.pType - local offRoadForm = vars.offRoadForm or 'default' - local onRoadForm = vars.onRoadForm or 'default' - - if routeProvided == false and #tempRoute > 0 then - local posStart = routines.getLeadPos(gpData) - - - useRoute[#useRoute + 1] = routines.ground.buildWP(posStart, offRoadForm, overRideSpeed) - for i = 1, #tempRoute do - local tempForm = tempRoute[i].action - local tempSpeed = tempRoute[i].speed - - if offRoadForm == 'default' then - tempForm = tempRoute[i].action - end - if onRoadForm == 'default' then - onRoadForm = 'On Road' - end - if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then - tempForm = onRoadForm - else - tempForm = offRoadForm - end - - if type(overRideSpeed) == 'number' then - tempSpeed = overRideSpeed - end - - - useRoute[#useRoute + 1] = routines.ground.buildWP(tempRoute[i], tempForm, tempSpeed) - end - - if pType and string.lower(pType) == 'doubleback' then - local curRoute = routines.utils.deepCopy(useRoute) - for i = #curRoute, 2, -1 do - useRoute[#useRoute + 1] = routines.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) - end - end - - useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP - end - - local cTask3 = {} - local newPatrol = {} - newPatrol.route = useRoute - newPatrol.gpData = gpData:getName() - cTask3[#cTask3 + 1] = 'routines.ground.patrolRoute(' - cTask3[#cTask3 + 1] = routines.utils.oneLineSerialize(newPatrol) - cTask3[#cTask3 + 1] = ')' - cTask3 = table.concat(cTask3) - local tempTask = { - id = 'WrappedAction', - params = { - action = { - id = 'Script', - params = { - command = cTask3, - - }, - }, - }, - } - - - useRoute[#useRoute].task = tempTask - routines.goRoute(gpData, useRoute) - - return -end - -routines.ground.patrol = function(gpData, pType, form, speed) - local vars = {} - - if type(gpData) == 'table' and gpData:getName() then - gpData = gpData:getName() - end - - vars.useGroupRoute = gpData - vars.gpData = gpData - vars.pType = pType - vars.offRoadForm = form - vars.speed = speed - - routines.ground.patrolRoute(vars) - - return -end - -function routines.GetUnitHeight( CheckUnit ) ---trace.f( "routines" ) - - local UnitPoint = CheckUnit:getPoint() - local UnitPosition = { x = UnitPoint.x, y = UnitPoint.z } - local UnitHeight = UnitPoint.y - - local LandHeight = land.getHeight( UnitPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - --trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight ) - - return UnitHeight - LandHeight - -end - - - -Su34Status = { status = {} } -boardMsgRed = { statusMsg = "" } -boardMsgAll = { timeMsg = "" } -SpawnSettings = {} -Su34MenuPath = {} -Su34Menus = 0 - - -function Su34AttackCarlVinson(groupName) ---trace.menu("", "Su34AttackCarlVinson") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupCarlVinson = Group.getByName("US Carl Vinson #001") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupCarlVinson ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupCarlVinson:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - Su34Status.status[groupName] = 1 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking carrier Carl Vinson. ', 10, 'RedStatus' .. groupName ) -end - -function Su34AttackWest(groupName) ---trace.f("","Su34AttackWest") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupShipWest1 = Group.getByName("US Ship West #001") - local groupShipWest2 = Group.getByName("US Ship West #002") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupShipWest1 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - if groupShipWest2 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - Su34Status.status[groupName] = 2 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the west. ', 10, 'RedStatus' .. groupName ) -end - -function Su34AttackNorth(groupName) ---trace.menu("","Su34AttackNorth") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupShipNorth1 = Group.getByName("US Ship North #001") - local groupShipNorth2 = Group.getByName("US Ship North #002") - local groupShipNorth3 = Group.getByName("US Ship North #003") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupShipNorth1 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - if groupShipNorth2 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - if groupShipNorth3 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth3:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - Su34Status.status[groupName] = 3 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the north. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Orbit(groupName) ---trace.menu("","Su34Orbit") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - controllerSu34:pushTask( {id = 'ControlledTask', params = { task = { id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } } ) - Su34Status.status[groupName] = 4 - MessageToRed( string.format('%s: ',groupName) .. 'In orbit and awaiting further instructions. ', 10, 'RedStatus' .. groupName ) -end - -function Su34TakeOff(groupName) ---trace.menu("","Su34TakeOff") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - Su34Status.status[groupName] = 8 - MessageToRed( string.format('%s: ',groupName) .. 'Take-Off. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Hold(groupName) ---trace.menu("","Su34Hold") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - Su34Status.status[groupName] = 5 - MessageToRed( string.format('%s: ',groupName) .. 'Holding Weapons. ', 10, 'RedStatus' .. groupName ) -end - -function Su34RTB(groupName) ---trace.menu("","Su34RTB") - Su34Status.status[groupName] = 6 - MessageToRed( string.format('%s: ',groupName) .. 'Return to Krasnodar. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Destroyed(groupName) ---trace.menu("","Su34Destroyed") - Su34Status.status[groupName] = 7 - MessageToRed( string.format('%s: ',groupName) .. 'Destroyed. ', 30, 'RedStatus' .. groupName ) -end - -function GroupAlive( groupName ) ---trace.menu("","GroupAlive") - local groupTest = Group.getByName( groupName ) - - local groupExists = false - - if groupTest then - groupExists = groupTest:isExist() - end - - --trace.r( "", "", { groupExists } ) - return groupExists -end - -function Su34IsDead() ---trace.f() - -end - -function Su34OverviewStatus() ---trace.menu("","Su34OverviewStatus") - local msg = "" - local currentStatus = 0 - local Exists = false - - for groupName, currentStatus in pairs(Su34Status.status) do - - env.info(('Su34 Overview Status: GroupName = ' .. groupName )) - Alive = GroupAlive( groupName ) - - if Alive then - if currentStatus == 1 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking carrier Carl Vinson. " - elseif currentStatus == 2 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking supporting ships in the west. " - elseif currentStatus == 3 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking invading ships in the north. " - elseif currentStatus == 4 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "In orbit and awaiting further instructions. " - elseif currentStatus == 5 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Holding Weapons. " - elseif currentStatus == 6 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Return to Krasnodar. " - elseif currentStatus == 7 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Destroyed. " - elseif currentStatus == 8 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Take-Off. " - end - else - if currentStatus == 7 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Destroyed. " - else - Su34Destroyed(groupName) - end - end - end - - boardMsgRed.statusMsg = msg -end - - -function UpdateBoardMsg() ---trace.f() - Su34OverviewStatus() - MessageToRed( boardMsgRed.statusMsg, 15, 'RedStatus' ) -end - -function MusicReset( flg ) ---trace.f() - trigger.action.setUserFlag(95,flg) -end - -function PlaneActivate(groupNameFormat, flg) ---trace.f() - local groupName = groupNameFormat .. string.format("#%03d", trigger.misc.getUserFlag(flg)) - --trigger.action.outText(groupName,10) - trigger.action.activateGroup(Group.getByName(groupName)) -end - -function Su34Menu(groupName) ---trace.f() - - --env.info(( 'Su34Menu(' .. groupName .. ')' )) - local groupSu34 = Group.getByName( groupName ) - - if Su34Status.status[groupName] == 1 or - Su34Status.status[groupName] == 2 or - Su34Status.status[groupName] == 3 or - Su34Status.status[groupName] == 4 or - Su34Status.status[groupName] == 5 then - if Su34MenuPath[groupName] == nil then - if planeMenuPath == nil then - planeMenuPath = missionCommands.addSubMenuForCoalition( - coalition.side.RED, - "SU-34 anti-ship flights", - nil - ) - end - Su34MenuPath[groupName] = missionCommands.addSubMenuForCoalition( - coalition.side.RED, - "Flight " .. groupName, - planeMenuPath - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack carrier Carl Vinson", - Su34MenuPath[groupName], - Su34AttackCarlVinson, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack ships in the west", - Su34MenuPath[groupName], - Su34AttackWest, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack ships in the north", - Su34MenuPath[groupName], - Su34AttackNorth, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Hold position and await instructions", - Su34MenuPath[groupName], - Su34Orbit, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Report status", - Su34MenuPath[groupName], - Su34OverviewStatus - ) - end - else - if Su34MenuPath[groupName] then - missionCommands.removeItemForCoalition(coalition.side.RED, Su34MenuPath[groupName]) - end - end -end - ---- Obsolete function, but kept to rework in framework. - -function ChooseInfantry ( TeleportPrefixTable, TeleportMax ) ---trace.f("Spawn") - --env.info(( 'ChooseInfantry: ' )) - - TeleportPrefixTableCount = #TeleportPrefixTable - TeleportPrefixTableIndex = math.random( 1, TeleportPrefixTableCount ) - - --env.info(( 'ChooseInfantry: TeleportPrefixTableIndex = ' .. TeleportPrefixTableIndex .. ' TeleportPrefixTableCount = ' .. TeleportPrefixTableCount .. ' TeleportMax = ' .. TeleportMax )) - - local TeleportFound = false - local TeleportLoop = true - local Index = TeleportPrefixTableIndex - local TeleportPrefix = '' - - while TeleportLoop do - TeleportPrefix = TeleportPrefixTable[Index] - if SpawnSettings[TeleportPrefix] then - if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then - SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 - TeleportFound = true - else - TeleportFound = false - end - else - SpawnSettings[TeleportPrefix] = {} - SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 - TeleportFound = true - end - if TeleportFound then - TeleportLoop = false - else - if Index < TeleportPrefixTableCount then - Index = Index + 1 - else - TeleportLoop = false - end - end - --env.info(( 'ChooseInfantry: Loop 1 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) - end - - if TeleportFound == false then - TeleportLoop = true - Index = 1 - while TeleportLoop do - TeleportPrefix = TeleportPrefixTable[Index] - if SpawnSettings[TeleportPrefix] then - if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then - SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 - TeleportFound = true - else - TeleportFound = false - end - else - SpawnSettings[TeleportPrefix] = {} - SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 - TeleportFound = true - end - if TeleportFound then - TeleportLoop = false - else - if Index < TeleportPrefixTableIndex then - Index = Index + 1 - else - TeleportLoop = false - end - end - --env.info(( 'ChooseInfantry: Loop 2 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) - end - end - - local TeleportGroupName = '' - if TeleportFound == true then - TeleportGroupName = TeleportPrefix .. string.format("#%03d", SpawnSettings[TeleportPrefix]['SpawnCount'] ) - else - TeleportGroupName = '' - end - - --env.info(('ChooseInfantry: TeleportGroupName = ' .. TeleportGroupName )) - --env.info(('ChooseInfantry: return')) - - return TeleportGroupName -end - -SpawnedInfantry = 0 - -function LandCarrier ( CarrierGroup, LandingZonePrefix ) ---trace.f() - --env.info(( 'LandCarrier: ' )) - --env.info(( 'LandCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) - --env.info(( 'LandCarrier: LandingZone = ' .. LandingZonePrefix )) - - local controllerGroup = CarrierGroup:getController() - - local LandingZone = trigger.misc.getZone(LandingZonePrefix) - local LandingZonePos = {} - LandingZonePos.x = LandingZone.point.x + math.random(LandingZone.radius * -1, LandingZone.radius) - LandingZonePos.y = LandingZone.point.z + math.random(LandingZone.radius * -1, LandingZone.radius) - - controllerGroup:pushTask( { id = 'Land', params = { point = LandingZonePos, durationFlag = true, duration = 10 } } ) - - --env.info(( 'LandCarrier: end' )) -end - -EscortCount = 0 -function EscortCarrier ( CarrierGroup, EscortPrefix, EscortLastWayPoint, EscortEngagementDistanceMax, EscortTargetTypes ) ---trace.f() - --env.info(( 'EscortCarrier: ' )) - --env.info(( 'EscortCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) - --env.info(( 'EscortCarrier: EscortPrefix = ' .. EscortPrefix )) - - local CarrierName = CarrierGroup:getName() - - local EscortMission = {} - local CarrierMission = {} - - local EscortMission = SpawnMissionGroup( EscortPrefix ) - local CarrierMission = SpawnMissionGroup( CarrierGroup:getName() ) - - if EscortMission ~= nil and CarrierMission ~= nil then - - EscortCount = EscortCount + 1 - EscortMissionName = string.format( EscortPrefix .. '#Escort %s', CarrierName ) - EscortMission.name = EscortMissionName - EscortMission.groupId = nil - EscortMission.lateActivation = false - EscortMission.taskSelected = false - - local EscortUnits = #EscortMission.units - for u = 1, EscortUnits do - EscortMission.units[u].name = string.format( EscortPrefix .. '#Escort %s %02d', CarrierName, u ) - EscortMission.units[u].unitId = nil - end - - - EscortMission.route.points[1].task = { id = "ComboTask", - params = - { - tasks = - { - [1] = - { - enabled = true, - auto = false, - id = "Escort", - number = 1, - params = - { - lastWptIndexFlagChangedManually = false, - groupId = CarrierGroup:getID(), - lastWptIndex = nil, - lastWptIndexFlag = false, - engagementDistMax = EscortEngagementDistanceMax, - targetTypes = EscortTargetTypes, - pos = - { - y = 20, - x = 20, - z = 0, - } -- end of ["pos"] - } -- end of ["params"] - } -- end of [1] - } -- end of ["tasks"] - } -- end of ["params"] - } -- end of ["task"] - - SpawnGroupAdd( EscortPrefix, EscortMission ) - - end -end - -function SendMessageToCarrier( CarrierGroup, CarrierMessage ) ---trace.f() - - if CarrierGroup ~= nil then - MessageToGroup( CarrierGroup, CarrierMessage, 30, 'Carrier/' .. CarrierGroup:getName() ) - end - -end - -function MessageToGroup( MsgGroup, MsgText, MsgTime, MsgName ) ---trace.f() - - if type(MsgGroup) == 'string' then - --env.info( 'MessageToGroup: Converted MsgGroup string "' .. MsgGroup .. '" into a Group structure.' ) - MsgGroup = Group.getByName( MsgGroup ) - end - - if MsgGroup ~= nil then - local MsgTable = {} - MsgTable.text = MsgText - MsgTable.displayTime = MsgTime - MsgTable.msgFor = { units = { MsgGroup:getUnits()[1]:getName() } } - MsgTable.name = MsgName - --routines.message.add( MsgTable ) - --env.info(('MessageToGroup: Message sent to ' .. MsgGroup:getUnits()[1]:getName() .. ' -> ' .. MsgText )) - end -end - -function MessageToUnit( UnitName, MsgText, MsgTime, MsgName ) ---trace.f() - - if UnitName ~= nil then - local MsgTable = {} - MsgTable.text = MsgText - MsgTable.displayTime = MsgTime - MsgTable.msgFor = { units = { UnitName } } - MsgTable.name = MsgName - --routines.message.add( MsgTable ) - end -end - -function MessageToAll( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "Message" ):ToCoalition( coalition.side.RED ):ToCoalition( coalition.side.BLUE ) -end - -function MessageToRed( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "To Red Coalition" ):ToCoalition( coalition.side.RED ) -end - -function MessageToBlue( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "To Blue Coalition" ):ToCoalition( coalition.side.RED ) -end - -function getCarrierHeight( CarrierGroup ) ---trace.f() - - if CarrierGroup ~= nil then - if table.getn(CarrierGroup:getUnits()) == 1 then - local CarrierUnit = CarrierGroup:getUnits()[1] - local CurrentPoint = CarrierUnit:getPoint() - - local CurrentPosition = { x = CurrentPoint.x, y = CurrentPoint.z } - local CarrierHeight = CurrentPoint.y - - local LandHeight = land.getHeight( CurrentPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - return CarrierHeight - LandHeight - else - return 999999 - end - else - return 999999 - end - -end - -function GetUnitHeight( CheckUnit ) ---trace.f() - - local UnitPoint = CheckUnit:getPoint() - local UnitPosition = { x = CurrentPoint.x, y = CurrentPoint.z } - local UnitHeight = CurrentPoint.y - - local LandHeight = land.getHeight( CurrentPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - return UnitHeight - LandHeight - -end - - -_MusicTable = {} -_MusicTable.Files = {} -_MusicTable.Queue = {} -_MusicTable.FileCnt = 0 - - -function MusicRegister( SndRef, SndFile, SndTime ) ---trace.f() - - env.info(( 'MusicRegister: SndRef = ' .. SndRef )) - env.info(( 'MusicRegister: SndFile = ' .. SndFile )) - env.info(( 'MusicRegister: SndTime = ' .. SndTime )) - - - _MusicTable.FileCnt = _MusicTable.FileCnt + 1 - - _MusicTable.Files[_MusicTable.FileCnt] = {} - _MusicTable.Files[_MusicTable.FileCnt].Ref = SndRef - _MusicTable.Files[_MusicTable.FileCnt].File = SndFile - _MusicTable.Files[_MusicTable.FileCnt].Time = SndTime - - if not _MusicTable.Function then - _MusicTable.Function = routines.scheduleFunction( MusicScheduler, { }, timer.getTime() + 10, 10) - end - -end - -function MusicToPlayer( SndRef, PlayerName, SndContinue ) ---trace.f() - - --env.info(( 'MusicToPlayer: SndRef = ' .. SndRef )) - - local PlayerUnits = AlivePlayerUnits() - for PlayerUnitIdx, PlayerUnit in pairs(PlayerUnits) do - local PlayerUnitName = PlayerUnit:getPlayerName() - --env.info(( 'MusicToPlayer: PlayerUnitName = ' .. PlayerUnitName )) - if PlayerName == PlayerUnitName then - PlayerGroup = PlayerUnit:getGroup() - if PlayerGroup then - --env.info(( 'MusicToPlayer: PlayerGroup = ' .. PlayerGroup:getName() )) - MusicToGroup( SndRef, PlayerGroup, SndContinue ) - end - break - end - end - - --env.info(( 'MusicToPlayer: end' )) - -end - -function MusicToGroup( SndRef, SndGroup, SndContinue ) ---trace.f() - - --env.info(( 'MusicToGroup: SndRef = ' .. SndRef )) - - if SndGroup ~= nil then - if _MusicTable and _MusicTable.FileCnt > 0 then - if SndGroup:isExist() then - if MusicCanStart(SndGroup:getUnit(1):getPlayerName()) then - --env.info(( 'MusicToGroup: OK for Sound.' )) - local SndIdx = 0 - if SndRef == '' then - --env.info(( 'MusicToGroup: SndRef as empty. Queueing at random.' )) - SndIdx = math.random( 1, _MusicTable.FileCnt ) - else - for SndIdx = 1, _MusicTable.FileCnt do - if _MusicTable.Files[SndIdx].Ref == SndRef then - break - end - end - end - --env.info(( 'MusicToGroup: SndIdx = ' .. SndIdx )) - --env.info(( 'MusicToGroup: Queueing Music ' .. _MusicTable.Files[SndIdx].File .. ' for Group ' .. SndGroup:getID() )) - trigger.action.outSoundForGroup( SndGroup:getID(), _MusicTable.Files[SndIdx].File ) - MessageToGroup( SndGroup, 'Playing ' .. _MusicTable.Files[SndIdx].File, 15, 'Music-' .. SndGroup:getUnit(1):getPlayerName() ) - - local SndQueueRef = SndGroup:getUnit(1):getPlayerName() - if _MusicTable.Queue[SndQueueRef] == nil then - _MusicTable.Queue[SndQueueRef] = {} - end - _MusicTable.Queue[SndQueueRef].Start = timer.getTime() - _MusicTable.Queue[SndQueueRef].PlayerName = SndGroup:getUnit(1):getPlayerName() - _MusicTable.Queue[SndQueueRef].Group = SndGroup - _MusicTable.Queue[SndQueueRef].ID = SndGroup:getID() - _MusicTable.Queue[SndQueueRef].Ref = SndIdx - _MusicTable.Queue[SndQueueRef].Continue = SndContinue - _MusicTable.Queue[SndQueueRef].Type = Group - end - end - end - end -end - -function MusicCanStart(PlayerName) ---trace.f() - - --env.info(( 'MusicCanStart:' )) - - local MusicOut = false - - if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then - --env.info(( 'MusicCanStart: PlayerName = ' .. PlayerName )) - local PlayerFound = false - local MusicStart = 0 - local MusicTime = 0 - for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do - if SndQueue.PlayerName == PlayerName then - PlayerFound = true - MusicStart = SndQueue.Start - MusicTime = _MusicTable.Files[SndQueue.Ref].Time - break - end - end - if PlayerFound then - --env.info(( 'MusicCanStart: MusicStart = ' .. MusicStart )) - --env.info(( 'MusicCanStart: MusicTime = ' .. MusicTime )) - --env.info(( 'MusicCanStart: timer.getTime() = ' .. timer.getTime() )) - - if MusicStart + MusicTime <= timer.getTime() then - MusicOut = true - end - else - MusicOut = true - end - end - - if MusicOut then - --env.info(( 'MusicCanStart: true' )) - else - --env.info(( 'MusicCanStart: false' )) - end - - return MusicOut -end - -function MusicScheduler() ---trace.scheduled("", "MusicScheduler") - - --env.info(( 'MusicScheduler:' )) - if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then - --env.info(( 'MusicScheduler: Walking Sound Queue.')) - for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do - if SndQueue.Continue then - if MusicCanStart(SndQueue.PlayerName) then - --env.info(('MusicScheduler: MusicToGroup')) - MusicToPlayer( '', SndQueue.PlayerName, true ) - end - end - end - end - -end - - -env.info(( 'Init: Scripts Loaded v1.1' )) - ---- This module contains derived utilities taken from the MIST framework, --- which are excellent tools to be reused in an OO environment!. --- --- ### Authors: --- --- * Grimes : Design & Programming of the MIST framework. --- --- ### Contributions: --- --- * FlightControl : Rework to OO framework --- --- @module Utils - - ---- @type SMOKECOLOR --- @field Green --- @field Red --- @field White --- @field Orange --- @field Blue - -SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR - ---- @type FLARECOLOR --- @field Green --- @field Red --- @field White --- @field Yellow - -FLARECOLOR = trigger.flareColor -- #FLARECOLOR - ---- Utilities static class. --- @type UTILS -UTILS = {} - - ---from http://lua-users.org/wiki/CopyTable -UTILS.DeepCopy = function(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - local objectreturn = _copy(object) - return objectreturn -end - - --- porting in Slmod's serialize_slmod2 -UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - - lookup_table = {} - - local function _Serialize( tbl ) - - if type(tbl) == 'table' then --function only works for tables! - - if lookup_table[tbl] then - return lookup_table[object] - end - - local tbl_str = {} - - lookup_table[tbl] = tbl_str - - tbl_str[#tbl_str + 1] = '{' - - for ind,val in pairs(tbl) do -- serialize its fields - local ind_str = {} - if type(ind) == "number" then - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = tostring(ind) - ind_str[#ind_str + 1] = ']=' - else --must be a string - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) - ind_str[#ind_str + 1] = ']=' - end - - local val_str = {} - if ((type(val) == 'number') or (type(val) == 'boolean')) then - val_str[#val_str + 1] = tostring(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'string' then - val_str[#val_str + 1] = routines.utils.basicSerialize(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'nil' then -- won't ever happen, right? - val_str[#val_str + 1] = 'nil,' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'table' then - if ind == "__index" then - -- tbl_str[#tbl_str + 1] = "__index" - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - - val_str[#val_str + 1] = _Serialize(val) - val_str[#val_str + 1] = ',' --I think this is right, I just added it - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - end - elseif type(val) == 'function' then - tbl_str[#tbl_str + 1] = "f() " .. tostring(ind) - tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) - env.info( debug.traceback() ) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) - else - return tostring(tbl) - end - end - - local objectreturn = _Serialize(tbl) - return objectreturn -end - ---porting in Slmod's "safestring" basic serialize -UTILS.BasicSerialize = function(s) - if s == nil then - return "\"\"" - else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) - return s - end - end -end - - -UTILS.ToDegree = function(angle) - return angle*180/math.pi -end - -UTILS.ToRadian = function(angle) - return angle*math.pi/180 -end - -UTILS.MetersToNM = function(meters) - return meters/1852 -end - -UTILS.MetersToFeet = function(meters) - return meters/0.3048 -end - -UTILS.NMToMeters = function(NM) - return NM*1852 -end - -UTILS.FeetToMeters = function(feet) - return feet*0.3048 -end - -UTILS.MpsToKnots = function(mps) - return mps*3600/1852 -end - -UTILS.MpsToKmph = function(mps) - return mps*3.6 -end - -UTILS.KnotsToMps = function(knots) - return knots*1852/3600 -end - -UTILS.KmphToMps = function(kmph) - return kmph/3.6 -end - ---[[acc: -in DM: decimal point of minutes. -In DMS: decimal point of seconds. -position after the decimal of the least significant digit: -So: -42.32 - acc of 2. -]] -UTILS.tostringLL = function( lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = UTILS.Round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - - else -- degrees, decimal minutes. - latMin = UTILS.Round(latMin, acc) - lonMin = UTILS.Round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end -end - - ---- From http://lua-users.org/wiki/SimpleRound --- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place -function UTILS.Round( num, idp ) - local mult = 10 ^ ( idp or 0 ) - return math.floor( num * mult + 0.5 ) / mult -end - --- porting in Slmod's dostring -function UTILS.DoString( s ) - local f, err = loadstring( s ) - if f then - return true, f() - else - return false, err - end -end ---- This module contains the BASE class. --- --- 1) @{#BASE} class --- ================= --- The @{#BASE} class is the super class for all the classes defined within MOOSE. --- --- It handles: --- --- * The construction and inheritance of child classes. --- * The tracing of objects during mission execution within the **DCS.log** file, under the **"Saved Games\DCS\Logs"** folder. --- --- Note: Normally you would not use the BASE class unless you are extending the MOOSE framework with new classes. --- --- ## 1.1) BASE constructor --- --- Any class derived from BASE, must use the @{Core.Base#BASE.New) constructor within the @{Core.Base#BASE.Inherit) method. --- See an example at the @{Core.Base#BASE.New} method how this is done. --- --- ## 1.2) BASE Trace functionality --- --- The BASE class contains trace methods to trace progress within a mission execution of a certain object. --- Note that these trace methods are inherited by each MOOSE class interiting BASE. --- As such, each object created from derived class from BASE can use the tracing functions to trace its execution. --- --- ### 1.2.1) Tracing functions --- --- There are basically 3 types of tracing methods available within BASE: --- --- * @{#BASE.F}: Trace the beginning of a function and its given parameters. An F is indicated at column 44 in the DCS.log file. --- * @{#BASE.T}: Trace further logic within a function giving optional variables or parameters. A T is indicated at column 44 in the DCS.log file. --- * @{#BASE.E}: Trace an exception within a function giving optional variables or parameters. An E is indicated at column 44 in the DCS.log file. An exception will always be traced. --- --- ### 1.2.2) Tracing levels --- --- There are 3 tracing levels within MOOSE. --- These tracing levels were defined to avoid bulks of tracing to be generated by lots of objects. --- --- As such, the F and T methods have additional variants to trace level 2 and 3 respectively: --- --- * @{#BASE.F2}: Trace the beginning of a function and its given parameters with tracing level 2. --- * @{#BASE.F3}: Trace the beginning of a function and its given parameters with tracing level 3. --- * @{#BASE.T2}: Trace further logic within a function giving optional variables or parameters with tracing level 2. --- * @{#BASE.T3}: Trace further logic within a function giving optional variables or parameters with tracing level 3. --- --- ### 1.2.3) Trace activation. --- --- Tracing can be activated in several ways: --- --- * Switch tracing on or off through the @{#BASE.TraceOnOff}() method. --- * Activate all tracing through the @{#BASE.TraceAll}() method. --- * Activate only the tracing of a certain class (name) through the @{#BASE.TraceClass}() method. --- * Activate only the tracing of a certain method of a certain class through the @{#BASE.TraceClassMethod}() method. --- * Activate only the tracing of a certain level through the @{#BASE.TraceLevel}() method. --- ### 1.2.4) Check if tracing is on. --- --- The method @{#BASE.IsTrace}() will validate if tracing is activated or not. --- --- ## 1.3 DCS simulator Event Handling --- --- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, --- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently. --- Therefore, the BASE class exposes the following event handling functions: --- --- * @{#BASE.EventOnBirth}(): Handle the birth of a new unit. --- * @{#BASE.EventOnBaseCaptured}(): Handle the capturing of an airbase or a helipad. --- * @{#BASE.EventOnCrash}(): Handle the crash of a unit. --- * @{#BASE.EventOnDead}(): Handle the death of a unit. --- * @{#BASE.EventOnEjection}(): Handle the ejection of a player out of an airplane. --- * @{#BASE.EventOnEngineShutdown}(): Handle the shutdown of an engine. --- * @{#BASE.EventOnEngineStartup}(): Handle the startup of an engine. --- * @{#BASE.EventOnHit}(): Handle the hit of a shell to a unit. --- * @{#BASE.EventOnHumanFailure}(): No a clue ... --- * @{#BASE.EventOnLand}(): Handle the event when a unit lands. --- * @{#BASE.EventOnMissionStart}(): Handle the start of the mission. --- * @{#BASE.EventOnPilotDead}(): Handle the event when a pilot is dead. --- * @{#BASE.EventOnPlayerComment}(): Handle the event when a player posts a comment. --- * @{#BASE.EventOnPlayerEnterUnit}(): Handle the event when a player enters a unit. --- * @{#BASE.EventOnPlayerLeaveUnit}(): Handle the event when a player leaves a unit. --- * @{#BASE.EventOnBirthPlayerMissionEnd}(): Handle the event when a player ends the mission. (Not a clue what that does). --- * @{#BASE.EventOnRefueling}(): Handle the event when a unit is refueling. --- * @{#BASE.EventOnShootingEnd}(): Handle the event when a unit starts shooting (guns). --- * @{#BASE.EventOnShootingStart}(): Handle the event when a unit ends shooting (guns). --- * @{#BASE.EventOnShot}(): Handle the event when a unit shot a missile. --- * @{#BASE.EventOnTakeOff}(): Handle the event when a unit takes off from a runway. --- * @{#BASE.EventOnTookControl}(): Handle the event when a player takes control of a unit. --- --- The EventOn() methods provide the @{Core.Event#EVENTDATA} structure to the event handling function. --- The @{Core.Event#EVENTDATA} structure contains an enriched data set of information about the event being handled. --- --- Find below an example of the prototype how to write an event handling function: --- --- CommandCenter:EventOnPlayerEnterUnit( --- --- @param #COMMANDCENTER self --- -- @param Core.Event#EVENTDATA EventData --- function( self, EventData ) --- local PlayerUnit = EventData.IniUnit --- for MissionID, Mission in pairs( self:GetMissions() ) do --- local Mission = Mission -- Tasking.Mission#MISSION --- Mission:JoinUnit( PlayerUnit ) --- Mission:ReportDetails() --- end --- end --- ) --- --- Note the function( self, EventData ). It takes two parameters: --- --- * self = the object that is handling the EventOnPlayerEnterUnit. --- * EventData = the @{Core.Event#EVENTDATA} structure, containing more information of the Event. --- --- ## 1.4) Class identification methods --- --- BASE provides methods to get more information of each object: --- --- * @{#BASE.GetClassID}(): Gets the ID (number) of the object. Each object created is assigned a number, that is incremented by one. --- * @{#BASE.GetClassName}(): Gets the name of the object, which is the name of the class the object was instantiated from. --- * @{#BASE.GetClassNameAndID}(): Gets the name and ID of the object. --- --- ## 1.10) BASE Inheritance (tree) support --- --- The following methods are available to support inheritance: --- --- * @{#BASE.Inherit}: Inherits from a class. --- * @{#BASE.GetParent}: Returns the parent object from the object it is handling, or nil if there is no parent object. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) --- YYYY-MM-DD: CLASS:**NewFunction( Params )** added --- --- Hereby the change log: --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * None. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming --- --- @module Base - - - -local _TraceOnOff = true -local _TraceLevel = 1 -local _TraceAll = false -local _TraceClass = {} -local _TraceClassMethod = {} - -local _ClassID = 0 - ---- The BASE Class --- @type BASE --- @field ClassName The name of the class. --- @field ClassID The ID number of the class. --- @field ClassNameAndID The name of the class concatenated with the ID number of the class. -BASE = { - ClassName = "BASE", - ClassID = 0, - Events = {}, - States = {} -} - ---- The Formation Class --- @type FORMATION --- @field Cone A cone formation. -FORMATION = { - Cone = "Cone" -} - - - --- @todo need to investigate if the deepCopy is really needed... Don't think so. -function BASE:New() - local self = routines.utils.deepCopy( self ) -- Create a new self instance - local MetaTable = {} - setmetatable( self, MetaTable ) - self.__index = self - _ClassID = _ClassID + 1 - self.ClassID = _ClassID - - - return self -end - -function BASE:_Destructor() - --self:E("_Destructor") - - --self:EventRemoveAll() -end - -function BASE:_SetDestructor() - - -- TODO: Okay, this is really technical... - -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak... - -- Therefore, I am parking this logic until I've properly discussed all this with the community. - --[[ - local proxy = newproxy(true) - local proxyMeta = getmetatable(proxy) - - proxyMeta.__gc = function () - env.info("In __gc for " .. self:GetClassNameAndID() ) - if self._Destructor then - self:_Destructor() - end - end - - -- keep the userdata from newproxy reachable until the object - -- table is about to be garbage-collected - then the __gc hook - -- will be invoked and the destructor called - rawset( self, '__proxy', proxy ) - --]] -end - ---- This is the worker method to inherit from a parent class. --- @param #BASE self --- @param Child is the Child class that inherits. --- @param #BASE Parent is the Parent class that the Child inherits from. --- @return #BASE Child -function BASE:Inherit( Child, Parent ) - local Child = routines.utils.deepCopy( Child ) - --local Parent = routines.utils.deepCopy( Parent ) - --local Parent = Parent - if Child ~= nil then - setmetatable( Child, Parent ) - Child.__index = Child - - Child:_SetDestructor() - end - --self:T( 'Inherited from ' .. Parent.ClassName ) - return Child -end - ---- This is the worker method to retrieve the Parent class. --- @param #BASE self --- @param #BASE Child is the Child class from which the Parent class needs to be retrieved. --- @return #BASE -function BASE:GetParent( Child ) - local Parent = getmetatable( Child ) --- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName ) - return Parent -end - ---- Get the ClassName + ClassID of the class instance. --- The ClassName + ClassID is formatted as '%s#%09d'. --- @param #BASE self --- @return #string The ClassName + ClassID of the class instance. -function BASE:GetClassNameAndID() - return string.format( '%s#%09d', self.ClassName, self.ClassID ) -end - ---- Get the ClassName of the class instance. --- @param #BASE self --- @return #string The ClassName of the class instance. -function BASE:GetClassName() - return self.ClassName -end - ---- Get the ClassID of the class instance. --- @param #BASE self --- @return #string The ClassID of the class instance. -function BASE:GetClassID() - return self.ClassID -end - ---- Set a new listener for the class. --- @param self --- @param Dcs.DCSTypes#Event Event --- @param #function EventFunction --- @return #BASE -function BASE:AddEvent( Event, EventFunction ) - self:F( Event ) - - self.Events[#self.Events+1] = {} - self.Events[#self.Events].Event = Event - self.Events[#self.Events].EventFunction = EventFunction - self.Events[#self.Events].EventEnabled = false - - return self -end - ---- Returns the event dispatcher --- @param #BASE self --- @return Core.Event#EVENT -function BASE:Event() - - return _EVENTDISPATCHER -end - ---- Remove all subscribed events --- @param #BASE self --- @return #BASE -function BASE:EventRemoveAll() - - _EVENTDISPATCHER:RemoveAll( self ) - - return self -end - ---- Subscribe to a S_EVENT\_SHOT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShot( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOT ) - - return self -end - ---- Subscribe to a S_EVENT\_HIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnHit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_HIT ) - - return self -end - ---- Subscribe to a S_EVENT\_TAKEOFF event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnTakeOff( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_TAKEOFF ) - - return self -end - ---- Subscribe to a S_EVENT\_LAND event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnLand( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_LAND ) - - return self -end - ---- Subscribe to a S_EVENT\_CRASH event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnCrash( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_CRASH ) - - return self -end - ---- Subscribe to a S_EVENT\_EJECTION event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEjection( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_EJECTION ) - - return self -end - - ---- Subscribe to a S_EVENT\_REFUELING event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnRefueling( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_REFUELING ) - - return self -end - ---- Subscribe to a S_EVENT\_DEAD event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnDead( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_DEAD ) - - return self -end - ---- Subscribe to a S_EVENT_PILOT\_DEAD event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPilotDead( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PILOT_DEAD ) - - return self -end - ---- Subscribe to a S_EVENT_BASE\_CAPTURED event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnBaseCaptured( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_BASE_CAPTURED ) - - return self -end - ---- Subscribe to a S_EVENT_MISSION\_START event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnMissionStart( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_MISSION_START ) - - return self -end - ---- Subscribe to a S_EVENT_MISSION\_END event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerMissionEnd( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_MISSION_END ) - - return self -end - ---- Subscribe to a S_EVENT_TOOK\_CONTROL event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnTookControl( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_TOOK_CONTROL ) - - return self -end - ---- Subscribe to a S_EVENT_REFUELING\_STOP event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnRefuelingStop( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_REFUELING_STOP ) - - return self -end - ---- Subscribe to a S_EVENT\_BIRTH event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnBirth( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_BIRTH ) - - return self -end - ---- Subscribe to a S_EVENT_HUMAN\_FAILURE event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnHumanFailure( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_HUMAN_FAILURE ) - - return self -end - ---- Subscribe to a S_EVENT_ENGINE\_STARTUP event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEngineStartup( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_ENGINE_STARTUP ) - - return self -end - ---- Subscribe to a S_EVENT_ENGINE\_SHUTDOWN event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEngineShutdown( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER_ENTER\_UNIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerEnterUnit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER_LEAVE\_UNIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerLeaveUnit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER\_COMMENT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerComment( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_COMMENT ) - - return self -end - ---- Subscribe to a S_EVENT_SHOOTING\_START event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShootingStart( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOOTING_START ) - - return self -end - ---- Subscribe to a S_EVENT_SHOOTING\_END event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShootingEnd( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOOTING_END ) - - return self -end - - - - - - - ---- Enable the event listeners for the class. --- @param #BASE self --- @return #BASE -function BASE:EnableEvents() - self:F( #self.Events ) - - for EventID, Event in pairs( self.Events ) do - Event.Self = self - Event.EventEnabled = true - end - self.Events.Handler = world.addEventHandler( self ) - - return self -end - - ---- Disable the event listeners for the class. --- @param #BASE self --- @return #BASE -function BASE:DisableEvents() - self:F() - - world.removeEventHandler( self ) - for EventID, Event in pairs( self.Events ) do - Event.Self = nil - Event.EventEnabled = false - end - - return self -end - - -local BaseEventCodes = { - "S_EVENT_SHOT", - "S_EVENT_HIT", - "S_EVENT_TAKEOFF", - "S_EVENT_LAND", - "S_EVENT_CRASH", - "S_EVENT_EJECTION", - "S_EVENT_REFUELING", - "S_EVENT_DEAD", - "S_EVENT_PILOT_DEAD", - "S_EVENT_BASE_CAPTURED", - "S_EVENT_MISSION_START", - "S_EVENT_MISSION_END", - "S_EVENT_TOOK_CONTROL", - "S_EVENT_REFUELING_STOP", - "S_EVENT_BIRTH", - "S_EVENT_HUMAN_FAILURE", - "S_EVENT_ENGINE_STARTUP", - "S_EVENT_ENGINE_SHUTDOWN", - "S_EVENT_PLAYER_ENTER_UNIT", - "S_EVENT_PLAYER_LEAVE_UNIT", - "S_EVENT_PLAYER_COMMENT", - "S_EVENT_SHOOTING_START", - "S_EVENT_SHOOTING_END", - "S_EVENT_MAX", -} - ---onEvent( {[1]="S_EVENT_BIRTH",[2]={["subPlace"]=5,["time"]=0,["initiator"]={["id_"]=16884480,},["place"]={["id_"]=5000040,},["id"]=15,["IniUnitName"]="US F-15C@RAMP-Air Support Mountains#001-01",},} --- Event = { --- id = enum world.event, --- time = Time, --- initiator = Unit, --- target = Unit, --- place = Unit, --- subPlace = enum world.BirthPlace, --- weapon = Weapon --- } - ---- Creation of a Birth Event. --- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. --- @param #string IniUnitName The initiating unit name. --- @param place --- @param subplace -function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace ) - self:F( { EventTime, Initiator, IniUnitName, place, subplace } ) - - local Event = { - id = world.event.S_EVENT_BIRTH, - time = EventTime, - initiator = Initiator, - IniUnitName = IniUnitName, - place = place, - subplace = subplace - } - - world.onEvent( Event ) -end - ---- Creation of a Crash Event. --- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. -function BASE:CreateEventCrash( EventTime, Initiator ) - self:F( { EventTime, Initiator } ) - - local Event = { - id = world.event.S_EVENT_CRASH, - time = EventTime, - initiator = Initiator, - } - - world.onEvent( Event ) -end - --- TODO: Complete Dcs.DCSTypes#Event structure. ---- The main event handling function... This function captures all events generated for the class. --- @param #BASE self --- @param Dcs.DCSTypes#Event event -function BASE:onEvent(event) - --self:F( { BaseEventCodes[event.id], event } ) - - if self then - for EventID, EventObject in pairs( self.Events ) do - if EventObject.EventEnabled then - --env.info( 'onEvent Table EventObject.Self = ' .. tostring(EventObject.Self) ) - --env.info( 'onEvent event.id = ' .. tostring(event.id) ) - --env.info( 'onEvent EventObject.Event = ' .. tostring(EventObject.Event) ) - if event.id == EventObject.Event then - if self == EventObject.Self then - if event.initiator and event.initiator:isExist() then - event.IniUnitName = event.initiator:getName() - end - if event.target and event.target:isExist() then - event.TgtUnitName = event.target:getName() - end - --self:T( { BaseEventCodes[event.id], event } ) - --EventObject.EventFunction( self, event ) - end - end - end - end - end -end - -function BASE:SetState( Object, StateName, State ) - - local ClassNameAndID = Object:GetClassNameAndID() - - self.States[ClassNameAndID] = self.States[ClassNameAndID] or {} - self.States[ClassNameAndID][StateName] = State - self:T2( { ClassNameAndID, StateName, State } ) - - return self.States[ClassNameAndID][StateName] -end - -function BASE:GetState( Object, StateName ) - - local ClassNameAndID = Object:GetClassNameAndID() - - if self.States[ClassNameAndID] then - local State = self.States[ClassNameAndID][StateName] or false - self:T2( { ClassNameAndID, StateName, State } ) - return State - end - - return nil -end - -function BASE:ClearState( Object, StateName ) - - local ClassNameAndID = Object:GetClassNameAndID() - if self.States[ClassNameAndID] then - self.States[ClassNameAndID][StateName] = nil - end -end - --- Trace section - --- Log a trace (only shown when trace is on) --- TODO: Make trace function using variable parameters. - ---- Set trace on or off --- Note that when trace is off, no debug statement is performed, increasing performance! --- When Moose is loaded statically, (as one file), tracing is switched off by default. --- So tracing must be switched on manually in your mission if you are using Moose statically. --- When moose is loading dynamically (for moose class development), tracing is switched on by default. --- @param #BASE self --- @param #boolean TraceOnOff Switch the tracing on or off. --- @usage --- -- Switch the tracing On --- BASE:TraceOnOff( true ) --- --- -- Switch the tracing Off --- BASE:TraceOnOff( false ) -function BASE:TraceOnOff( TraceOnOff ) - _TraceOnOff = TraceOnOff -end - - ---- Enquires if tracing is on (for the class). --- @param #BASE self --- @return #boolean -function BASE:IsTrace() - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - return true - else - return false - end -end - ---- Set trace level --- @param #BASE self --- @param #number Level -function BASE:TraceLevel( Level ) - _TraceLevel = Level - self:E( "Tracing level " .. Level ) -end - ---- Trace all methods in MOOSE --- @param #BASE self --- @param #boolean TraceAll true = trace all methods in MOOSE. -function BASE:TraceAll( TraceAll ) - - _TraceAll = TraceAll - - if _TraceAll then - self:E( "Tracing all methods in MOOSE " ) - else - self:E( "Switched off tracing all methods in MOOSE" ) - end -end - ---- Set tracing for a class --- @param #BASE self --- @param #string Class -function BASE:TraceClass( Class ) - _TraceClass[Class] = true - _TraceClassMethod[Class] = {} - self:E( "Tracing class " .. Class ) -end - ---- Set tracing for a specific method of class --- @param #BASE self --- @param #string Class --- @param #string Method -function BASE:TraceClassMethod( Class, Method ) - if not _TraceClassMethod[Class] then - _TraceClassMethod[Class] = {} - _TraceClassMethod[Class].Method = {} - end - _TraceClassMethod[Class].Method[Method] = true - self:E( "Tracing method " .. Method .. " of class " .. Class ) -end - ---- Trace a function call. This function is private. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - - local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) - local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then - local LineCurrent = 0 - if DebugInfoCurrent.currentline then - LineCurrent = DebugInfoCurrent.currentline - end - local LineFrom = 0 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) - end - end -end - ---- Trace a function call. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 1 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - - ---- Trace a function call level 2. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F2( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 2 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function call level 3. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F3( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 3 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - - local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) - local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then - local LineCurrent = 0 - if DebugInfoCurrent.currentline then - LineCurrent = DebugInfoCurrent.currentline - end - local LineFrom = 0 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) - end - end -end - ---- Trace a function logic level 1. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 1 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - - ---- Trace a function logic level 2. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T2( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 2 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function logic level 3. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T3( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 3 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Log an exception which will be traced always. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:E( Arguments ) - - if debug then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - local LineCurrent = DebugInfoCurrent.currentline - local LineFrom = -1 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) - end - -end - - - ---- This module contains the SCHEDULER class. --- --- # 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE} --- --- The @{Core.Scheduler#SCHEDULER} class creates schedule. --- --- ## 1.1) SCHEDULER constructor --- --- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters: --- --- * @{Core.Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection. --- * @{Core.Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. --- * @{Core.Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- * @{Core.Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- --- ## 1.2) SCHEDULER timer stopping and (re-)starting. --- --- The SCHEDULER can be stopped and restarted with the following methods: --- --- * @{Core.Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started. --- * @{Core.Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped. --- --- ## 1.3) Create a new schedule --- --- With @{Core.Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned. --- --- === --- --- ### Contributions: --- --- * FlightControl : Concept & Testing --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Test Missions: --- --- * SCH - Scheduler --- --- === --- --- @module Scheduler - - ---- The SCHEDULER class --- @type SCHEDULER --- @field #number ScheduleID the ID of the scheduler. --- @extends Core.Base#BASE -SCHEDULER = { - ClassName = "SCHEDULER", - Schedules = {}, -} - ---- SCHEDULER constructor. --- @param #SCHEDULER self --- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. --- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. --- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. --- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. --- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. --- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. --- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. --- @return #SCHEDULER self --- @return #number The ScheduleID of the planned schedule. -function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( { Start, Repeat, RandomizeFactor, Stop } ) - - local ScheduleID = nil - - self.MasterObject = SchedulerObject - - if SchedulerFunction then - ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - end - - return self, ScheduleID -end - ---function SCHEDULER:_Destructor() --- --self:E("_Destructor") --- --- _SCHEDULEDISPATCHER:RemoveSchedule( self.CallID ) ---end - ---- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also. --- @param #SCHEDULER self --- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. --- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. --- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. --- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. --- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. --- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. --- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. --- @return #number The ScheduleID of the planned schedule. -function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - self:F2( { Start, Repeat, RandomizeFactor, Stop } ) - self:T3( { SchedulerArguments } ) - - local ObjectName = "-" - if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then - ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID - end - self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) - self.SchedulerObject = SchedulerObject - - local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( - self, - SchedulerFunction, - SchedulerArguments, - Start, - Repeat, - RandomizeFactor, - Stop - ) - - self.Schedules[#self.Schedules+1] = ScheduleID - - return ScheduleID -end - ---- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Start( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Start( self, ScheduleID ) -end - ---- Stops the schedules or a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Stop( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Stop( self, ScheduleID ) -end - ---- Removes a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Remove( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Remove( self, ScheduleID ) -end - - - - - - - - - - - - - - - ---- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER. --- --- === --- --- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects. --- --- This class is tricky and needs some thorought explanation. --- SCHEDULE classes are used to schedule functions for objects, or as persistent objects. --- The SCHEDULEDISPATCHER class ensures that: --- --- - Scheduled functions are planned according the SCHEDULER object parameters. --- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters. --- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters. --- --- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection: --- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER --- object is _persistent_ within memory. --- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection! --- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected. --- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object, --- these will not be executed anymore when the SCHEDULER object has been destroyed. --- --- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object. --- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER. --- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method. --- The Schedule() method returns the CallID that is the reference ID for each planned schedule. --- --- === --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module ScheduleDispatcher - ---- The SCHEDULEDISPATCHER structure --- @type SCHEDULEDISPATCHER -SCHEDULEDISPATCHER = { - ClassName = "SCHEDULEDISPATCHER", - CallID = 0, -} - -function SCHEDULEDISPATCHER:New() - local self = BASE:Inherit( self, BASE:New() ) - self:F3() - return self -end - ---- Add a Schedule to the ScheduleDispatcher. --- The development of this method was really tidy. --- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified. --- Nothing of this code should be modified without testing it thoroughly. --- @param #SCHEDULEDISPATCHER self --- @param Core.Scheduler#SCHEDULER Scheduler -function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop ) - self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } ) - - self.CallID = self.CallID + 1 - - -- Initialize the ObjectSchedulers array, which is a weakly coupled table. - -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.PersistentSchedulers = self.PersistentSchedulers or {} - - -- Initialize the ObjectSchedulers array, which is a weakly coupled table. - -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) - - if Scheduler.MasterObject then - self.ObjectSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) - else - self.PersistentSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) - end - - self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) - self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} - self.Schedule[Scheduler][self.CallID] = {} - self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction - self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments - self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 ) - self.Schedule[Scheduler][self.CallID].Start = Start + .1 - self.Schedule[Scheduler][self.CallID].Repeat = Repeat - self.Schedule[Scheduler][self.CallID].Randomize = Randomize - self.Schedule[Scheduler][self.CallID].Stop = Stop - - self:T3( self.Schedule[Scheduler][self.CallID] ) - - self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID ) - self:F2( CallID ) - - local ErrorHandler = function( errmsg ) - env.info( "Error in timer function: " .. errmsg ) - if debug ~= nil then - env.info( debug.traceback() ) - end - return errmsg - end - - local Scheduler = self.ObjectSchedulers[CallID] - if not Scheduler then - Scheduler = self.PersistentSchedulers[CallID] - end - - self:T3( { Scheduler = Scheduler } ) - - if Scheduler then - - local Schedule = self.Schedule[Scheduler][CallID] - - self:T3( { Schedule = Schedule } ) - - local ScheduleObject = Scheduler.SchedulerObject - --local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID() - local ScheduleFunction = Schedule.Function - local ScheduleArguments = Schedule.Arguments - local Start = Schedule.Start - local Repeat = Schedule.Repeat or 0 - local Randomize = Schedule.Randomize or 0 - local Stop = Schedule.Stop or 0 - local ScheduleID = Schedule.ScheduleID - - local Status, Result - if ScheduleObject then - local function Timer() - return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) ) - end - Status, Result = xpcall( Timer, ErrorHandler ) - else - local function Timer() - return ScheduleFunction( unpack( ScheduleArguments ) ) - end - Status, Result = xpcall( Timer, ErrorHandler ) - end - - local CurrentTime = timer.getTime() - local StartTime = CurrentTime + Start - - 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 - local ScheduleTime = - CurrentTime + - Repeat + - math.random( - - ( Randomize * Repeat / 2 ), - ( Randomize * Repeat / 2 ) - ) + - 0.01 - self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } ) - return ScheduleTime -- returns the next time the function needs to be called. - else - self:Stop( Scheduler, CallID ) - end - else - self:Stop( Scheduler, CallID ) - end - else - self:E( "Scheduled obscolete call for CallID: " .. CallID ) - end - - return nil - end - - self:Start( Scheduler, self.CallID ) - - return self.CallID -end - -function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID ) - self:F2( { Remove = CallID, Scheduler = Scheduler } ) - - if CallID then - self:Stop( Scheduler, CallID ) - self.Schedule[Scheduler][CallID] = nil - end -end - -function SCHEDULEDISPATCHER:Start( Scheduler, CallID ) - self:F2( { Start = CallID, Scheduler = Scheduler } ) - - if CallID then - local Schedule = self.Schedule[Scheduler] - Schedule[CallID].ScheduleID = timer.scheduleFunction( - Schedule[CallID].CallHandler, - CallID, - timer.getTime() + Schedule[CallID].Start - ) - else - for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do - self:Start( Scheduler, CallID ) -- Recursive - end - end -end - -function SCHEDULEDISPATCHER:Stop( Scheduler, CallID ) - self:F2( { Stop = CallID, Scheduler = Scheduler } ) - - if CallID then - local Schedule = self.Schedule[Scheduler] - timer.removeFunction( Schedule[CallID].ScheduleID ) - else - for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do - self:Stop( Scheduler, CallID ) -- Recursive - end - end -end - - - ---- This module contains the EVENT class. --- --- === --- --- Takes care of EVENT dispatching between DCS events and event handling functions defined in MOOSE classes. --- --- === --- --- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these): --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module Event - ---- The EVENT structure --- @type EVENT --- @field #EVENT.Events Events -EVENT = { - ClassName = "EVENT", - ClassID = 0, -} - -local _EVENTCODES = { - "S_EVENT_SHOT", - "S_EVENT_HIT", - "S_EVENT_TAKEOFF", - "S_EVENT_LAND", - "S_EVENT_CRASH", - "S_EVENT_EJECTION", - "S_EVENT_REFUELING", - "S_EVENT_DEAD", - "S_EVENT_PILOT_DEAD", - "S_EVENT_BASE_CAPTURED", - "S_EVENT_MISSION_START", - "S_EVENT_MISSION_END", - "S_EVENT_TOOK_CONTROL", - "S_EVENT_REFUELING_STOP", - "S_EVENT_BIRTH", - "S_EVENT_HUMAN_FAILURE", - "S_EVENT_ENGINE_STARTUP", - "S_EVENT_ENGINE_SHUTDOWN", - "S_EVENT_PLAYER_ENTER_UNIT", - "S_EVENT_PLAYER_LEAVE_UNIT", - "S_EVENT_PLAYER_COMMENT", - "S_EVENT_SHOOTING_START", - "S_EVENT_SHOOTING_END", - "S_EVENT_MAX", -} - ---- The Event structure --- @type EVENTDATA --- @field id --- @field initiator --- @field target --- @field weapon --- @field IniDCSUnit --- @field IniDCSUnitName --- @field Wrapper.Unit#UNIT IniUnit --- @field #string IniUnitName --- @field IniDCSGroup --- @field IniDCSGroupName --- @field TgtDCSUnit --- @field TgtDCSUnitName --- @field Wrapper.Unit#UNIT TgtUnit --- @field #string TgtUnitName --- @field TgtDCSGroup --- @field TgtDCSGroupName --- @field Weapon --- @field WeaponName --- @field WeaponTgtDCSUnit - ---- The Events structure --- @type EVENT.Events --- @field #number IniUnit - -function EVENT:New() - local self = BASE:Inherit( self, BASE:New() ) - self:F2() - self.EventHandler = world.addEventHandler( self ) - return self -end - -function EVENT:EventText( EventID ) - - local EventText = _EVENTCODES[EventID] - - return EventText -end - - ---- Initializes the Events structure for the event --- @param #EVENT self --- @param Dcs.DCSWorld#world.event EventID --- @param Core.Base#BASE EventClass --- @return #EVENT.Events -function EVENT:Init( EventID, EventClass ) - self:F3( { _EVENTCODES[EventID], EventClass } ) - - if not self.Events[EventID] then - -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. - self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) - - end - - if not self.Events[EventID][EventClass] then - self.Events[EventID][EventClass] = setmetatable( {}, { __mode = "k" } ) - end - return self.Events[EventID][EventClass] -end - ---- Removes an Events entry --- @param #EVENT self --- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param Dcs.DCSWorld#world.event EventID --- @return #EVENT.Events -function EVENT:Remove( EventClass, EventID ) - self:F3( { EventClass, _EVENTCODES[EventID] } ) - - local EventClass = EventClass - self.Events[EventID][EventClass] = nil -end - ---- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- @param #EVENT self --- @param Core.Base#BASE EventObject -function EVENT:RemoveAll( EventObject ) - self:F3( { EventObject:GetClassNameAndID() } ) - - local EventClass = EventObject:GetClassNameAndID() - for EventID, EventData in pairs( self.Events ) do - self.Events[EventID][EventClass] = nil - end -end - - - ---- Create an OnDead event handler for a group --- @param #EVENT self --- @param #table EventTemplate --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param EventClass The instance of the class for which the event is. --- @param #function OnEventFunction --- @return #EVENT -function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, OnEventFunction ) - self:F2( EventTemplate.name ) - - for EventUnitID, EventUnit in pairs( EventTemplate.units ) do - OnEventFunction( self, EventUnit.name, EventFunction, EventClass ) - end - return self -end - ---- Set a new listener for an S_EVENT_X event independent from a unit or a weapon. --- @param #EVENT self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param Core.Base#BASE EventClass The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided. --- @param EventID --- @return #EVENT -function EVENT:OnEventGeneric( EventFunction, EventClass, EventID ) - self:F2( { EventID } ) - - local Event = self:Init( EventID, EventClass ) - Event.EventFunction = EventFunction - Event.EventClass = EventClass - return self -end - - ---- Set a new listener for an S_EVENT_X event --- @param #EVENT self --- @param #string EventDCSUnitName --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param EventID --- @return #EVENT -function EVENT:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, EventID ) - self:F2( EventDCSUnitName ) - - local Event = self:Init( EventID, EventClass ) - if not Event.IniUnit then - Event.IniUnit = {} - end - Event.IniUnit[EventDCSUnitName] = {} - Event.IniUnit[EventDCSUnitName].EventFunction = EventFunction - Event.IniUnit[EventDCSUnitName].EventClass = EventClass - return self -end - -do -- OnBirth - - --- Create an OnBirth event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnBirthForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_BIRTH event, and registers the unit born. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirth( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - --- Set a new listener for an S_EVENT_BIRTH event. - -- @param #EVENT self - -- @param #string EventDCSUnitName The id of the unit for the event to be handled. - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirthForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - --- Stop listening to S_EVENT_BIRTH event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirthRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - -end - -do -- OnCrash - - --- Create an OnCrash event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnCrashForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_CRASH event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnCrash( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_CRASH ) - - return self - end - - --- Set a new listener for an S_EVENT_CRASH event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnCrashForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_CRASH ) - - return self - end - - --- Stop listening to S_EVENT_CRASH event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnCrashRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_CRASH ) - - return self - end - -end - -do -- OnDead - - --- Create an OnDead event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnDeadForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_DEAD event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnDead( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - - --- Set a new listener for an S_EVENT_DEAD event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnDeadForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - --- Stop listening to S_EVENT_DEAD event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnDeadRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - -end - -do -- OnPilotDead - - --- Set a new listener for an S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPilotDead( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - - --- Set a new listener for an S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPilotDeadForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - - --- Stop listening to S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPilotDeadRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - -end - -do -- OnLand - --- Create an OnLand event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnLandForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_LAND event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnLandForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_LAND ) - - return self - end - - --- Stop listening to S_EVENT_LAND event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnLandRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_LAND ) - - return self - end - - -end - -do -- OnTakeOff - --- Create an OnTakeOff event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnTakeOffForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_TAKEOFF event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnTakeOffForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_TAKEOFF ) - - return self - end - - --- Stop listening to S_EVENT_TAKEOFF event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnTakeOffRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_TAKEOFF ) - - return self - end - - -end - -do -- OnEngineShutDown - - --- Create an OnDead event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnEngineShutDownForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_ENGINE_SHUTDOWN event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineShutDownForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self - end - - --- Stop listening to S_EVENT_ENGINE_SHUTDOWN event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnEngineShutDownRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self - end - -end - -do -- OnEngineStartUp - - --- Set a new listener for an S_EVENT_ENGINE_STARTUP event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineStartUpForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_ENGINE_STARTUP ) - - return self - end - - --- Stop listening to S_EVENT_ENGINE_STARTUP event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnEngineStartUpRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_ENGINE_STARTUP ) - - return self - end - -end - -do -- OnShot - --- Set a new listener for an S_EVENT_SHOT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnShot( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - --- Set a new listener for an S_EVENT_SHOT event for a unit. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnShotForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - --- Stop listening to S_EVENT_SHOT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnShotRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - -end - -do -- OnHit - - --- Set a new listener for an S_EVENT_HIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnHit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_HIT ) - - return self - end - - --- Set a new listener for an S_EVENT_HIT event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnHitForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_HIT ) - - return self - end - - --- Stop listening to S_EVENT_HIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnHitRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_HIT ) - - return self - end - -end - -do -- OnPlayerEnterUnit - - --- Set a new listener for an S_EVENT_PLAYER_ENTER_UNIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPlayerEnterUnit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self - end - - --- Stop listening to S_EVENT_PLAYER_ENTER_UNIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPlayerEnterRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self - end - -end - -do -- OnPlayerLeaveUnit - --- Set a new listener for an S_EVENT_PLAYER_LEAVE_UNIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPlayerLeaveUnit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self - end - - --- Stop listening to S_EVENT_PLAYER_LEAVE_UNIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPlayerLeaveRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self - end - -end - - - ---- @param #EVENT self --- @param #EVENTDATA Event -function EVENT:onEvent( Event ) - - if self and self.Events and self.Events[Event.id] then - if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then - Event.IniDCSUnit = Event.initiator - Event.IniDCSGroup = Event.IniDCSUnit:getGroup() - Event.IniDCSUnitName = Event.IniDCSUnit:getName() - Event.IniUnitName = Event.IniDCSUnitName - Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName ) - if not Event.IniUnit then - -- Unit can be a CLIENT. Most likely this will be the case ... - Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true ) - end - Event.IniDCSGroupName = "" - if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then - Event.IniDCSGroupName = Event.IniDCSGroup:getName() - end - end - if Event.target then - if Event.target and Event.target:getCategory() == Object.Category.UNIT then - Event.TgtDCSUnit = Event.target - Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup() - Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() - Event.TgtUnitName = Event.TgtDCSUnitName - Event.TgtUnit = UNIT:FindByName( Event.TgtDCSUnitName ) - Event.TgtDCSGroupName = "" - if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then - Event.TgtDCSGroupName = Event.TgtDCSGroup:getName() - end - end - end - if Event.weapon then - Event.Weapon = Event.weapon - Event.WeaponName = Event.Weapon:getTypeName() - --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() - end - self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } ) - - -- Okay, we got the event from DCS. Now loop the self.Events[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. - for EventClass, EventData in pairs( self.Events[Event.id] ) do - -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. - if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then - self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName } ) - EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) - else - -- If the EventData is not bound to a specific unit, then call the EventClass EventFunction. - -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. - if Event.IniDCSUnit and not EventData.IniUnit then - if EventClass == EventData.EventClass then - self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID() } ) - EventData.EventFunction( EventData.EventClass, Event ) - end - end - end - end - else - self:E( { _EVENTCODES[Event.id], Event } ) - end -end - ---- This module contains the MENU classes. --- --- There is a small note... When you see a class like MENU_COMMAND_COALITION with COMMAND in italic, it acutally represents it like this: `MENU_COMMAND_COALITION`. --- --- === --- --- DCS Menus can be managed using the MENU classes. --- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scanerios where you need to --- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing --- menus is not a easy feat if you have complex menu hierarchies defined. --- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy. --- On top, MOOSE implements **variable parameter** passing for command menus. --- --- There are basically two different MENU class types that you need to use: --- --- ### To manage **main menus**, the classes begin with **MENU_**: --- --- * @{Core.Menu#MENU_MISSION}: Manages main menus for whole mission file. --- * @{Core.Menu#MENU_COALITION}: Manages main menus for whole coalition. --- * @{Core.Menu#MENU_GROUP}: Manages main menus for GROUPs. --- * @{Core.Menu#MENU_CLIENT}: Manages main menus for CLIENTs. This manages menus for units with the skill level "Client". --- --- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**: --- --- * @{Core.Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. --- * @{Core.Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. --- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. --- * @{Core.Menu#MENU_CLIENT_COMMAND}: Manages command menus for CLIENTs. This manages menus for units with the skill level "Client". --- --- === --- --- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these): --- --- 1) MENU_ BASE abstract base classes (don't use them) --- ==================================================== --- The underlying base menu classes are **NOT** to be used within your missions. --- These are simply abstract base classes defining a couple of fields that are used by the --- derived MENU_ classes to manage menus. --- --- 1.1) @{Core.Menu#MENU_BASE} class, extends @{Core.Base#BASE} --- -------------------------------------------------- --- The @{#MENU_BASE} class defines the main MENU class where other MENU classes are derived from. --- --- 1.2) @{Core.Menu#MENU_COMMAND_BASE} class, extends @{Core.Base#BASE} --- ---------------------------------------------------------- --- The @{#MENU_COMMAND_BASE} class defines the main MENU class where other MENU COMMAND_ classes are derived from, in order to set commands. --- --- === --- --- **The next menus define the MENU classes that you can use within your missions.** --- --- 2) MENU MISSION classes --- ====================== --- The underlying classes manage the menus for a complete mission file. --- --- 2.1) @{Menu#MENU_MISSION} class, extends @{Core.Menu#MENU_BASE} --- --------------------------------------------------------- --- The @{Core.Menu#MENU_MISSION} class manages the main menus for a complete mission. --- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. --- --- 2.2) @{Menu#MENU_MISSION_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------- --- The @{Core.Menu#MENU_MISSION_COMMAND} class manages the command menus for a complete mission, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. --- --- === --- --- 3) MENU COALITION classes --- ========================= --- The underlying classes manage the menus for whole coalitions. --- --- 3.1) @{Menu#MENU_COALITION} class, extends @{Core.Menu#MENU_BASE} --- ------------------------------------------------------------ --- The @{Core.Menu#MENU_COALITION} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. --- --- 3.2) @{Menu#MENU_COALITION_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ---------------------------------------------------------------------------- --- The @{Core.Menu#MENU_COALITION_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. --- --- === --- --- 4) MENU GROUP classes --- ===================== --- The underlying classes manage the menus for groups. Note that groups can be inactive, alive or can be destroyed. --- --- 4.1) @{Menu#MENU_GROUP} class, extends @{Core.Menu#MENU_BASE} --- -------------------------------------------------------- --- The @{Core.Menu#MENU_GROUP} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. --- --- 4.2) @{Menu#MENU_GROUP_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------ --- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. --- --- === --- --- 5) MENU CLIENT classes --- ====================== --- The underlying classes manage the menus for units with skill level client or player. --- --- 5.1) @{Menu#MENU_CLIENT} class, extends @{Core.Menu#MENU_BASE} --- --------------------------------------------------------- --- The @{Core.Menu#MENU_CLIENT} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}. --- --- 5.2) @{Menu#MENU_CLIENT_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------- --- The @{Core.Menu#MENU_CLIENT_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT_COMMAND.Remove}. --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module Menu - - -do -- MENU_BASE - - --- The MENU_BASE class - -- @type MENU_BASE - -- @extends Base#BASE - MENU_BASE = { - ClassName = "MENU_BASE", - MenuPath = nil, - MenuText = "", - MenuParentPath = nil - } - - --- Consructor - function MENU_BASE:New( MenuText, ParentMenu ) - - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, BASE:New() ) - - self.MenuPath = nil - self.MenuText = MenuText - self.MenuParentPath = MenuParentPath - - return self - end - -end - -do -- MENU_COMMAND_BASE - - --- The MENU_COMMAND_BASE class - -- @type MENU_COMMAND_BASE - -- @field #function MenuCallHandler - -- @extends Menu#MENU_BASE - MENU_COMMAND_BASE = { - ClassName = "MENU_COMMAND_BASE", - CommandMenuFunction = nil, - CommandMenuArgument = nil, - MenuCallHandler = nil, - } - - --- Constructor - function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self.CommandMenuFunction = CommandMenuFunction - self.MenuCallHandler = function( CommandMenuArguments ) - self.CommandMenuFunction( unpack( CommandMenuArguments ) ) - end - - return self - end - -end - - -do -- MENU_MISSION - - --- The MENU_MISSION class - -- @type MENU_MISSION - -- @extends Menu#MENU_BASE - MENU_MISSION = { - ClassName = "MENU_MISSION" - } - - --- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file. - -- @param #MENU_MISSION self - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). - -- @return #MENU_MISSION self - function MENU_MISSION:New( MenuText, ParentMenu ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self:F( { MenuText, ParentMenu } ) - - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - self:T( { MenuText } ) - - self.MenuPath = missionCommands.addSubMenu( MenuText, self.MenuParentPath ) - - self:T( { self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - - return self - end - - --- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept! - -- @param #MENU_MISSION self - -- @return #MENU_MISSION self - function MENU_MISSION:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and the sub menus recursively of this MENU_MISSION. - -- @param #MENU_MISSION self - -- @return #nil - function MENU_MISSION:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - missionCommands.removeItem( self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - - return nil - end - -end - -do -- MENU_MISSION_COMMAND - - --- The MENU_MISSION_COMMAND class - -- @type MENU_MISSION_COMMAND - -- @extends Menu#MENU_COMMAND_BASE - MENU_MISSION_COMMAND = { - ClassName = "MENU_MISSION_COMMAND" - } - - --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. - -- @param #MENU_MISSION_COMMAND self - -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_MISSION ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. - -- @return #MENU_MISSION_COMMAND self - function MENU_MISSION_COMMAND:New( MenuText, ParentMenu, CommandMenuFunction, ... ) - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { MenuText, CommandMenuFunction, arg } ) - - - self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a radio command item for a coalition - -- @param #MENU_MISSION_COMMAND self - -- @return #nil - function MENU_MISSION_COMMAND:Remove() - self:F( self.MenuPath ) - - missionCommands.removeItem( self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - return nil - end - -end - - - -do -- MENU_COALITION - - --- The MENU_COALITION class - -- @type MENU_COALITION - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the planes within the red coalition. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- - -- local Plane1 = CLIENT:FindByName( "Plane 1" ) - -- local Plane2 = CLIENT:FindByName( "Plane 2" ) - -- - -- - -- -- This would create a menu for the red coalition under the main DCS "Others" menu. - -- local MenuCoalitionRed = MENU_COALITION:New( coalition.side.RED, "Manage Menus" ) - -- - -- - -- local function ShowStatus( StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- Plane1:Message( StatusText, 15 ) - -- Plane2:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus -- Menu#MENU_COALITION - -- local MenuStatusShow -- Menu#MENU_COALITION_COMMAND - -- - -- local function RemoveStatusMenu() - -- MenuStatus:Remove() - -- end - -- - -- local function AddStatusMenu() - -- - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus = MENU_COALITION:New( coalition.side.RED, "Status for Planes" ) - -- MenuStatusShow = MENU_COALITION_COMMAND:New( coalition.side.RED, "Show Status", MenuStatus, ShowStatus, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- local MenuAdd = MENU_COALITION_COMMAND:New( coalition.side.RED, "Add Status Menu", MenuCoalitionRed, AddStatusMenu ) - -- local MenuRemove = MENU_COALITION_COMMAND:New( coalition.side.RED, "Remove Status Menu", MenuCoalitionRed, RemoveStatusMenu ) - MENU_COALITION = { - ClassName = "MENU_COALITION" - } - - --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. - -- @param #MENU_COALITION self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). - -- @return #MENU_COALITION self - function MENU_COALITION:New( Coalition, MenuText, ParentMenu ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self:F( { Coalition, MenuText, ParentMenu } ) - - self.Coalition = Coalition - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - self:T( { MenuText } ) - - self.MenuPath = missionCommands.addSubMenuForCoalition( Coalition, MenuText, self.MenuParentPath ) - - self:T( { self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - - return self - end - - --- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept! - -- @param #MENU_COALITION self - -- @return #MENU_COALITION self - function MENU_COALITION:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and the sub menus recursively of this MENU_COALITION. - -- @param #MENU_COALITION self - -- @return #nil - function MENU_COALITION:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - - return nil - end - -end - -do -- MENU_COALITION_COMMAND - - --- The MENU_COALITION_COMMAND class - -- @type MENU_COALITION_COMMAND - -- @extends Menu#MENU_COMMAND_BASE - MENU_COALITION_COMMAND = { - ClassName = "MENU_COALITION_COMMAND" - } - - --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. - -- @param #MENU_COALITION_COMMAND self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. - -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_COALITION ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. - -- @return #MENU_COALITION_COMMAND self - function MENU_COALITION_COMMAND:New( Coalition, MenuText, ParentMenu, CommandMenuFunction, ... ) - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - - self.MenuCoalition = Coalition - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { MenuText, CommandMenuFunction, arg } ) - - - self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a radio command item for a coalition - -- @param #MENU_COALITION_COMMAND self - -- @return #nil - function MENU_COALITION_COMMAND:Remove() - self:F( self.MenuPath ) - - missionCommands.removeItemForCoalition( self.MenuCoalition, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - return nil - end - -end - -do -- MENU_CLIENT - - -- This local variable is used to cache the menus registered under clients. - -- Menus don't dissapear when clients are destroyed and restarted. - -- So every menu for a client created must be tracked so that program logic accidentally does not create - -- the same menus twice during initialization logic. - -- These menu classes are handling this logic with this variable. - local _MENUCLIENTS = {} - - --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. - -- @type MENU_CLIENT - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the two clients of planes. - -- -- Each client will receive a different menu structure. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- -- And play with the Add and Remove menu options. - -- - -- -- Note that in multi player, this will only work after the DCS clients bug is solved. - -- - -- local function ShowStatus( PlaneClient, StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- PlaneClient:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus = {} - -- - -- local function RemoveStatusMenu( MenuClient ) - -- local MenuClientName = MenuClient:GetName() - -- MenuStatus[MenuClientName]:Remove() - -- end - -- - -- --- @param Wrapper.Client#CLIENT MenuClient - -- local function AddStatusMenu( MenuClient ) - -- local MenuClientName = MenuClient:GetName() - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus[MenuClientName] = MENU_CLIENT:New( MenuClient, "Status for Planes" ) - -- MENU_CLIENT_COMMAND:New( MenuClient, "Show Status", MenuStatus[MenuClientName], ShowStatus, MenuClient, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneClient = CLIENT:FindByName( "Plane 1" ) - -- if PlaneClient and PlaneClient:IsAlive() then - -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneClient ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneClient ) - -- end - -- end, {}, 10, 10 ) - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneClient = CLIENT:FindByName( "Plane 2" ) - -- if PlaneClient and PlaneClient:IsAlive() then - -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneClient ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneClient ) - -- end - -- end, {}, 10, 10 ) - MENU_CLIENT = { - ClassName = "MENU_CLIENT" - } - - --- MENU_CLIENT constructor. Creates a new radio menu item for a client. - -- @param #MENU_CLIENT self - -- @param Wrapper.Client#CLIENT Client The Client owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. - -- @return #MENU_CLIENT self - function MENU_CLIENT:New( Client, MenuText, ParentMenu ) - - -- Arrange meta tables - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, MenuParentPath ) ) - self:F( { Client, MenuText, ParentMenu } ) - - self.MenuClient = Client - self.MenuClientGroupID = Client:GetClientGroupID() - self.MenuParentPath = MenuParentPath - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) - - local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText - if MenuPath[MenuPathID] then - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) - end - - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) - MenuPath[MenuPathID] = self.MenuPath - - self:T( { Client:GetClientGroupName(), self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - return self - end - - --- Removes the sub menus recursively of this @{#MENU_CLIENT}. - -- @param #MENU_CLIENT self - -- @return #MENU_CLIENT self - function MENU_CLIENT:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the sub menus recursively of this MENU_CLIENT. - -- @param #MENU_CLIENT self - -- @return #nil - function MENU_CLIENT:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then - MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil - end - - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - return nil - end - - - --- The MENU_CLIENT_COMMAND class - -- @type MENU_CLIENT_COMMAND - -- @extends Menu#MENU_COMMAND - MENU_CLIENT_COMMAND = { - ClassName = "MENU_CLIENT_COMMAND" - } - - --- MENU_CLIENT_COMMAND constructor. Creates a new radio command item for a client, which can invoke a function with parameters. - -- @param #MENU_CLIENT_COMMAND self - -- @param Wrapper.Client#CLIENT Client The Client owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #MENU_BASE ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. - -- @return Menu#MENU_CLIENT_COMMAND self - function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, ... ) - - -- Arrange meta tables - - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, MenuParentPath, CommandMenuFunction, arg ) ) -- Menu#MENU_CLIENT_COMMAND - - self.MenuClient = MenuClient - self.MenuClientGroupID = MenuClient:GetClientGroupID() - self.MenuParentPath = MenuParentPath - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, arg } ) - - local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText - if MenuPath[MenuPathID] then - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) - end - - self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler, arg ) - MenuPath[MenuPathID] = self.MenuPath - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a menu structure for a client. - -- @param #MENU_CLIENT_COMMAND self - -- @return #nil - function MENU_CLIENT_COMMAND:Remove() - self:F( self.MenuPath ) - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then - MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil - end - - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - return nil - end -end - ---- MENU_GROUP - -do - -- This local variable is used to cache the menus registered under groups. - -- Menus don't dissapear when groups for players are destroyed and restarted. - -- So every menu for a client created must be tracked so that program logic accidentally does not create. - -- the same menus twice during initialization logic. - -- These menu classes are handling this logic with this variable. - local _MENUGROUPS = {} - - --- The MENU_GROUP class - -- @type MENU_GROUP - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the two groups of planes. - -- -- Each group will receive a different menu structure. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- -- And play with the Add and Remove menu options. - -- - -- -- Note that in multi player, this will only work after the DCS groups bug is solved. - -- - -- local function ShowStatus( PlaneGroup, StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- PlaneGroup:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus = {} - -- - -- local function RemoveStatusMenu( MenuGroup ) - -- local MenuGroupName = MenuGroup:GetName() - -- MenuStatus[MenuGroupName]:Remove() - -- end - -- - -- --- @param Wrapper.Group#GROUP MenuGroup - -- local function AddStatusMenu( MenuGroup ) - -- local MenuGroupName = MenuGroup:GetName() - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus[MenuGroupName] = MENU_GROUP:New( MenuGroup, "Status for Planes" ) - -- MENU_GROUP_COMMAND:New( MenuGroup, "Show Status", MenuStatus[MenuGroupName], ShowStatus, MenuGroup, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneGroup = GROUP:FindByName( "Plane 1" ) - -- if PlaneGroup and PlaneGroup:IsAlive() then - -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneGroup ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneGroup ) - -- end - -- end, {}, 10, 10 ) - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneGroup = GROUP:FindByName( "Plane 2" ) - -- if PlaneGroup and PlaneGroup:IsAlive() then - -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneGroup ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneGroup ) - -- end - -- end, {}, 10, 10 ) - -- - MENU_GROUP = { - ClassName = "MENU_GROUP" - } - - --- MENU_GROUP constructor. Creates a new radio menu item for a group. - -- @param #MENU_GROUP self - -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. - -- @return #MENU_GROUP self - function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu ) - - -- Determine if the menu was not already created and already visible at the group. - -- If it is visible, then return the cached self, otherwise, create self and cache it. - - MenuGroup._Menus = MenuGroup._Menus or {} - local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText - if MenuGroup._Menus[Path] then - self = MenuGroup._Menus[Path] - else - self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - MenuGroup._Menus[Path] = self - - self.Menus = {} - - self.MenuGroup = MenuGroup - self.Path = Path - self.MenuGroupID = MenuGroup:GetID() - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { "Adding Menu ", MenuText, self.MenuParentPath } ) - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, self.MenuParentPath ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - end - - self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) - - return self - end - - --- Removes the sub menus recursively of this MENU_GROUP. - -- @param #MENU_GROUP self - -- @return #MENU_GROUP self - function MENU_GROUP:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and sub menus recursively of this MENU_GROUP. - -- @param #MENU_GROUP self - -- @return #nil - function MENU_GROUP:Remove() - self:F( { self.MenuGroupID, self.MenuPath } ) - - self:RemoveSubMenus() - - if self.MenuGroup._Menus[self.Path] then - self = self.MenuGroup._Menus[self.Path] - - missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - self:E( self.MenuGroup._Menus[self.Path] ) - self.MenuGroup._Menus[self.Path] = nil - self = nil - end - return nil - end - - - --- The MENU_GROUP_COMMAND class - -- @type MENU_GROUP_COMMAND - -- @extends Menu#MENU_BASE - MENU_GROUP_COMMAND = { - ClassName = "MENU_GROUP_COMMAND" - } - - --- Creates a new radio command item for a group - -- @param #MENU_GROUP_COMMAND self - -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. - -- @param MenuText The text for the menu. - -- @param ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. - -- @return Menu#MENU_GROUP_COMMAND self - function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, ... ) - - MenuGroup._Menus = MenuGroup._Menus or {} - local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText - if MenuGroup._Menus[Path] then - self = MenuGroup._Menus[Path] - else - self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - MenuGroup._Menus[Path] = self - - self.Path = Path - self.MenuGroup = MenuGroup - self.MenuGroupID = MenuGroup:GetID() - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { "Adding Command Menu ", MenuText, self.MenuParentPath } ) - self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - end - - self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) - - return self - end - - --- Removes a menu structure for a group. - -- @param #MENU_GROUP_COMMAND self - -- @return #nil - function MENU_GROUP_COMMAND:Remove() - self:F( { self.MenuGroupID, self.MenuPath } ) - - if self.MenuGroup._Menus[self.Path] then - self = self.MenuGroup._Menus[self.Path] - - missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - self:E( self.MenuGroup._Menus[self.Path] ) - self.MenuGroup._Menus[self.Path] = nil - self = nil - end - - return nil - end - -end - ---- This module contains the ZONE classes, inherited from @{Core.Zone#ZONE_BASE}. --- There are essentially two core functions that zones accomodate: --- --- * Test if an object is within the zone boundaries. --- * Provide the zone behaviour. Some zones are static, while others are moveable. --- --- The object classes are using the zone classes to test the zone boundaries, which can take various forms: --- --- * Test if completely within the zone. --- * Test if partly within the zone (for @{Wrapper.Group#GROUP} objects). --- * Test if not in the zone. --- * Distance to the nearest intersecting point of the zone. --- * Distance to the center of the zone. --- * ... --- --- Each of these ZONE classes have a zone name, and specific parameters defining the zone type: --- --- * @{Core.Zone#ZONE_BASE}: The ZONE_BASE class defining the base for all other zone classes. --- * @{Core.Zone#ZONE_RADIUS}: The ZONE_RADIUS class defined by a zone name, a location and a radius. --- * @{Core.Zone#ZONE}: The ZONE class, defined by the zone name as defined within the Mission Editor. --- * @{Core.Zone#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- * @{Core.Zone#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. --- * @{Core.Zone#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- --- === --- --- 1) @{Core.Zone#ZONE_BASE} class, extends @{Core.Base#BASE} --- ================================================ --- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. --- --- ### 1.1) Each zone has a name: --- --- * @{#ZONE_BASE.GetName}(): Returns the name of the zone. --- --- ### 1.2) Each zone implements two polymorphic functions defined in @{Core.Zone#ZONE_BASE}: --- --- * @{#ZONE_BASE.IsPointVec2InZone}(): Returns if a @{Core.Point#POINT_VEC2} is within the zone. --- * @{#ZONE_BASE.IsPointVec3InZone}(): Returns if a @{Core.Point#POINT_VEC3} is within the zone. --- --- ### 1.3) A zone has a probability factor that can be set to randomize a selection between zones: --- --- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% ) --- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% ) --- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate. --- --- ### 1.4) A zone manages Vectors: --- --- * @{#ZONE_BASE.GetVec2}(): Returns the @{Dcs.DCSTypes#Vec2} coordinate of the zone. --- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- --- ### 1.5) A zone has a bounding square: --- --- * @{#ZONE_BASE.GetBoundingSquare}(): Get the outer most bounding square of the zone. --- --- ### 1.6) A zone can be marked: --- --- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color. --- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color. --- --- === --- --- 2) @{Core.Zone#ZONE_RADIUS} class, extends @{Core.Zone#ZONE_BASE} --- ======================================================= --- The ZONE_RADIUS class defined by a zone name, a location and a radius. --- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties. --- --- ### 2.1) @{Core.Zone#ZONE_RADIUS} constructor: --- --- * @{#ZONE_BASE.New}(): Constructor. --- --- ### 2.2) Manage the radius of the zone: --- --- * @{#ZONE_BASE.SetRadius}(): Sets the radius of the zone. --- * @{#ZONE_BASE.GetRadius}(): Returns the radius of the zone. --- --- ### 2.3) Manage the location of the zone: --- --- * @{#ZONE_BASE.SetVec2}(): Sets the @{Dcs.DCSTypes#Vec2} of the zone. --- * @{#ZONE_BASE.GetVec2}(): Returns the @{Dcs.DCSTypes#Vec2} of the zone. --- * @{#ZONE_BASE.GetVec3}(): Returns the @{Dcs.DCSTypes#Vec3} of the zone, taking an additional height parameter. --- --- === --- --- 3) @{Core.Zone#ZONE} class, extends @{Core.Zone#ZONE_RADIUS} --- ========================================== --- The ZONE class, defined by the zone name as defined within the Mission Editor. --- This class implements the inherited functions from {Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 4) @{Core.Zone#ZONE_UNIT} class, extends @{Core.Zone#ZONE_RADIUS} --- ======================================================= --- The ZONE_UNIT class defined by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 5) @{Core.Zone#ZONE_GROUP} class, extends @{Core.Zone#ZONE_RADIUS} --- ======================================================= --- The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. The current leader of the group defines the center of the zone. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 6) @{Core.Zone#ZONE_POLYGON_BASE} class, extends @{Core.Zone#ZONE_BASE} --- ======================================================== --- The ZONE_POLYGON_BASE class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. --- --- === --- --- 7) @{Core.Zone#ZONE_POLYGON} class, extends @{Core.Zone#ZONE_POLYGON_BASE} --- ================================================================ --- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-15: ZONE_BASE:**GetName()** added. --- --- 2016-08-15: ZONE_BASE:**SetZoneProbability( ZoneProbability )** added. --- --- 2016-08-15: ZONE_BASE:**GetZoneProbability()** added. --- --- 2016-08-15: ZONE_BASE:**GetZoneMaybe()** added. --- --- === --- --- @module Zone --- @author FlightControl - - ---- The ZONE_BASE class --- @type ZONE_BASE --- @field #string ZoneName Name of the zone. --- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. --- @extends Core.Base#BASE -ZONE_BASE = { - ClassName = "ZONE_BASE", - ZoneName = "", - ZoneProbability = 1, - } - - ---- The ZONE_BASE.BoundingSquare --- @type ZONE_BASE.BoundingSquare --- @field Dcs.DCSTypes#Distance x1 The lower x coordinate (left down) --- @field Dcs.DCSTypes#Distance y1 The lower y coordinate (left down) --- @field Dcs.DCSTypes#Distance x2 The higher x coordinate (right up) --- @field Dcs.DCSTypes#Distance y2 The higher y coordinate (right up) - - ---- ZONE_BASE constructor --- @param #ZONE_BASE self --- @param #string ZoneName Name of the zone. --- @return #ZONE_BASE self -function ZONE_BASE:New( ZoneName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( ZoneName ) - - self.ZoneName = ZoneName - - return self -end - ---- Returns the name of the zone. --- @param #ZONE_BASE self --- @return #string The name of the zone. -function ZONE_BASE:GetName() - self:F2() - - return self.ZoneName -end ---- Returns if a location is within the zone. --- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_BASE:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - return false -end - ---- Returns if a point is within the zone. --- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. --- @return #boolean true if the point is within the zone. -function ZONE_BASE:IsPointVec3InZone( Vec3 ) - self:F2( Vec3 ) - - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) - - return InZone -end - ---- Returns the @{Dcs.DCSTypes#Vec2} coordinate of the zone. --- @param #ZONE_BASE self --- @return #nil. -function ZONE_BASE:GetVec2() - self:F2( self.ZoneName ) - - return nil -end ---- Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- @param #ZONE_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinates. -function ZONE_BASE:GetRandomVec2() - return nil -end - ---- Get the bounding square the zone. --- @param #ZONE_BASE self --- @return #nil The bounding square. -function ZONE_BASE:GetBoundingSquare() - --return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } - return nil -end - - ---- Smokes the zone boundaries in a color. --- @param #ZONE_BASE self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. -function ZONE_BASE:SmokeZone( SmokeColor ) - self:F2( SmokeColor ) - -end - ---- Set the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. -function ZONE_BASE:SetZoneProbability( ZoneProbability ) - self:F2( ZoneProbability ) - - self.ZoneProbability = ZoneProbability or 1 - return self -end - ---- Get the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @return #number A value between 0 and 1. 0 = 0% and 1 = 100% probability. -function ZONE_BASE:GetZoneProbability() - self:F2() - - return self.ZoneProbability -end - ---- Get the zone taking into account the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor. --- @return #nil The zone is not selected taking into account the randomization probability factor. -function ZONE_BASE:GetZoneMaybe() - self:F2() - - local Randomization = math.random() - if Randomization <= self.ZoneProbability then - return self - else - return nil - end -end - - ---- The ZONE_RADIUS class, defined by a zone name, a location and a radius. --- @type ZONE_RADIUS --- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone. --- @field Dcs.DCSTypes#Distance Radius The radius of the zone. --- @extends Core.Zone#ZONE_BASE -ZONE_RADIUS = { - ClassName="ZONE_RADIUS", - } - ---- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius. --- @param #ZONE_RADIUS self --- @param #string ZoneName Name of the zone. --- @param Dcs.DCSTypes#Vec2 Vec2 The location of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:New( ZoneName, Vec2, Radius ) - local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) - self:F( { ZoneName, Vec2, Radius } ) - - self.Radius = Radius - self.Vec2 = Vec2 - - return self -end - ---- Smokes the zone boundaries in a color. --- @param #ZONE_RADIUS self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. --- @param #number Points (optional) The amount of points in the circle. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:SmokeZone( SmokeColor, Points ) - self:F2( SmokeColor ) - - local Point = {} - local Vec2 = self:GetVec2() - - Points = Points and Points or 360 - - local Angle - local RadialBase = math.pi*2 - - for Angle = 0, 360, 360 / Points do - local Radial = Angle * RadialBase / 360 - Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() - Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() - POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor ) - end - - return self -end - - ---- Flares the zone boundaries in a color. --- @param #ZONE_RADIUS self --- @param Utilities.Utils#FLARECOLOR FlareColor The flare color. --- @param #number Points (optional) The amount of points in the circle. --- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth ) - self:F2( { FlareColor, Azimuth } ) - - local Point = {} - local Vec2 = self:GetVec2() - - Points = Points and Points or 360 - - local Angle - local RadialBase = math.pi*2 - - for Angle = 0, 360, 360 / Points do - local Radial = Angle * RadialBase / 360 - Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() - Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() - POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth ) - end - - return self -end - ---- Returns the radius of the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Distance The radius of the zone. -function ZONE_RADIUS:GetRadius() - self:F2( self.ZoneName ) - - self:T2( { self.Radius } ) - - return self.Radius -end - ---- Sets the radius of the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return Dcs.DCSTypes#Distance The radius of the zone. -function ZONE_RADIUS:SetRadius( Radius ) - self:F2( self.ZoneName ) - - self.Radius = Radius - self:T2( { self.Radius } ) - - return self.Radius -end - ---- Returns the @{Dcs.DCSTypes#Vec2} of the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Vec2 The location of the zone. -function ZONE_RADIUS:GetVec2() - self:F2( self.ZoneName ) - - self:T2( { self.Vec2 } ) - - return self.Vec2 -end - ---- Sets the @{Dcs.DCSTypes#Vec2} of the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The new location of the zone. --- @return Dcs.DCSTypes#Vec2 The new location of the zone. -function ZONE_RADIUS:SetVec2( Vec2 ) - self:F2( self.ZoneName ) - - self.Vec2 = Vec2 - - self:T2( { self.Vec2 } ) - - return self.Vec2 -end - ---- Returns the @{Dcs.DCSTypes#Vec3} of the ZONE_RADIUS. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. -function ZONE_RADIUS:GetVec3( Height ) - self:F2( { self.ZoneName, Height } ) - - Height = Height or 0 - local Vec2 = self:GetVec2() - - local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } - - self:T2( { Vec3 } ) - - return Vec3 -end - - ---- Returns if a location is within the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_RADIUS:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - local ZoneVec2 = self:GetVec2() - - if ZoneVec2 then - if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then - return true - end - end - - return false -end - ---- Returns if a point is within the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. --- @return #boolean true if the point is within the zone. -function ZONE_RADIUS:IsPointVec3InZone( Vec3 ) - self:F2( Vec3 ) - - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) - - return InZone -end - ---- Returns a random location within the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Vec2 The random location within the zone. -function ZONE_RADIUS:GetRandomVec2() - self:F( self.ZoneName ) - - local Point = {} - local Vec2 = self:GetVec2() - - local angle = math.random() * math.pi*2; - Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { Point } ) - - return Point -end - - - ---- The ZONE class, defined by the zone name as defined within the Mission Editor. The location and the radius are automatically collected from the mission settings. --- @type ZONE --- @extends Core.Zone#ZONE_RADIUS -ZONE = { - ClassName="ZONE", - } - - ---- Constructor of ZONE, taking the zone name. --- @param #ZONE self --- @param #string ZoneName The name of the zone as defined within the mission editor. --- @return #ZONE -function ZONE:New( ZoneName ) - - local Zone = trigger.misc.getZone( ZoneName ) - - if not Zone then - error( "Zone " .. ZoneName .. " does not exist." ) - return nil - end - - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, { x = Zone.point.x, y = Zone.point.z }, Zone.radius ) ) - self:F( ZoneName ) - - self.Zone = Zone - - return self -end - - ---- The ZONE_UNIT class defined by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- @type ZONE_UNIT --- @field Wrapper.Unit#UNIT ZoneUNIT --- @extends Core.Zone#ZONE_RADIUS -ZONE_UNIT = { - ClassName="ZONE_UNIT", - } - ---- Constructor to create a ZONE_UNIT instance, taking the zone name, a zone unit and a radius. --- @param #ZONE_UNIT self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Unit#UNIT ZoneUNIT The unit as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_UNIT self -function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) ) - self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } ) - - self.ZoneUNIT = ZoneUNIT - self.LastVec2 = ZoneUNIT:GetVec2() - - return self -end - - ---- Returns the current location of the @{Wrapper.Unit#UNIT}. --- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Unit#UNIT}location. -function ZONE_UNIT:GetVec2() - self:F( self.ZoneName ) - - local ZoneVec2 = self.ZoneUNIT:GetVec2() - if ZoneVec2 then - self.LastVec2 = ZoneVec2 - return ZoneVec2 - else - return self.LastVec2 - end - - self:T( { ZoneVec2 } ) - - return nil -end - ---- Returns a random location within the zone. --- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The random location within the zone. -function ZONE_UNIT:GetRandomVec2() - self:F( self.ZoneName ) - - local RandomVec2 = {} - local Vec2 = self.ZoneUNIT:GetVec2() - - if not Vec2 then - Vec2 = self.LastVec2 - end - - local angle = math.random() * math.pi*2; - RandomVec2.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - RandomVec2.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { RandomVec2 } ) - - return RandomVec2 -end - ---- Returns the @{Dcs.DCSTypes#Vec3} of the ZONE_UNIT. --- @param #ZONE_UNIT self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. -function ZONE_UNIT:GetVec3( Height ) - self:F2( self.ZoneName ) - - Height = Height or 0 - - local Vec2 = self:GetVec2() - - local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } - - self:T2( { Vec3 } ) - - return Vec3 -end - ---- The ZONE_GROUP class defined by a zone around a @{Group}, taking the average center point of all the units within the Group, with a radius. --- @type ZONE_GROUP --- @field Wrapper.Group#GROUP ZoneGROUP --- @extends Core.Zone#ZONE_RADIUS -ZONE_GROUP = { - ClassName="ZONE_GROUP", - } - ---- Constructor to create a ZONE_GROUP instance, taking the zone name, a zone @{Wrapper.Group#GROUP} and a radius. --- @param #ZONE_GROUP self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Group#GROUP ZoneGROUP The @{Group} as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_GROUP self -function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) ) - self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } ) - - self.ZoneGROUP = ZoneGROUP - - return self -end - - ---- Returns the current location of the @{Group}. --- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location. -function ZONE_GROUP:GetVec2() - self:F( self.ZoneName ) - - local ZoneVec2 = self.ZoneGROUP:GetVec2() - - self:T( { ZoneVec2 } ) - - return ZoneVec2 -end - ---- Returns a random location within the zone of the @{Group}. --- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Group} location. -function ZONE_GROUP:GetRandomVec2() - self:F( self.ZoneName ) - - local Point = {} - local Vec2 = self.ZoneGROUP:GetVec2() - - local angle = math.random() * math.pi*2; - Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { Point } ) - - return Point -end - - - --- Polygons - ---- The ZONE_POLYGON_BASE class defined by an array of @{Dcs.DCSTypes#Vec2}, forming a polygon. --- @type ZONE_POLYGON_BASE --- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{Dcs.DCSTypes#Vec2}. --- @extends Core.Zone#ZONE_BASE -ZONE_POLYGON_BASE = { - ClassName="ZONE_POLYGON_BASE", - } - ---- A points array. --- @type ZONE_POLYGON_BASE.ListVec2 --- @list - ---- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{Dcs.DCSTypes#Vec2}, forming a polygon. --- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. --- @param #ZONE_POLYGON_BASE self --- @param #string ZoneName Name of the zone. --- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{Dcs.DCSTypes#Vec2}, forming a polygon.. --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) - local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) - self:F( { ZoneName, PointsArray } ) - - local i = 0 - - self.Polygon = {} - - for i = 1, #PointsArray do - self.Polygon[i] = {} - self.Polygon[i].x = PointsArray[i].x - self.Polygon[i].y = PointsArray[i].y - end - - return self -end - ---- Flush polygon coordinates as a table in DCS.log. --- @param #ZONE_POLYGON_BASE self --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:Flush() - self:F2() - - self:E( { Polygon = self.ZoneName, Coordinates = self.Polygon } ) - - return self -end - - ---- Smokes the zone boundaries in a color. --- @param #ZONE_POLYGON_BASE self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:SmokeZone( SmokeColor ) - self:F2( SmokeColor ) - - local i - local j - local Segments = 10 - - i = 1 - j = #self.Polygon - - while i <= #self.Polygon do - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) - - local DeltaX = self.Polygon[j].x - self.Polygon[i].x - local DeltaY = self.Polygon[j].y - self.Polygon[i].y - - for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. - local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) - local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) - POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor ) - end - j = i - i = i + 1 - end - - return self -end - - - - ---- Returns if a location is within the zone. --- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html --- @param #ZONE_POLYGON_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_POLYGON_BASE:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - local Next - local Prev - local InPolygon = false - - Next = 1 - Prev = #self.Polygon - - while Next <= #self.Polygon do - self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) - if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and - ( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) - ) then - InPolygon = not InPolygon - end - self:T2( { InPolygon = InPolygon } ) - Prev = Next - Next = Next + 1 - end - - self:T( { InPolygon = InPolygon } ) - return InPolygon -end - ---- Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- @param #ZONE_POLYGON_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinate. -function ZONE_POLYGON_BASE:GetRandomVec2() - self:F2() - - --- It is a bit tricky to find a random point within a polygon. Right now i am doing it the dirty and inefficient way... - local Vec2Found = false - local Vec2 - local BS = self:GetBoundingSquare() - - self:T2( BS ) - - while Vec2Found == false do - Vec2 = { x = math.random( BS.x1, BS.x2 ), y = math.random( BS.y1, BS.y2 ) } - self:T2( Vec2 ) - if self:IsPointVec2InZone( Vec2 ) then - Vec2Found = true - end - end - - self:T2( Vec2 ) - - return Vec2 -end - ---- Get the bounding square the zone. --- @param #ZONE_POLYGON_BASE self --- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square. -function ZONE_POLYGON_BASE:GetBoundingSquare() - - local x1 = self.Polygon[1].x - local y1 = self.Polygon[1].y - local x2 = self.Polygon[1].x - local y2 = self.Polygon[1].y - - for i = 2, #self.Polygon do - self:T2( { self.Polygon[i], x1, y1, x2, y2 } ) - x1 = ( x1 > self.Polygon[i].x ) and self.Polygon[i].x or x1 - x2 = ( x2 < self.Polygon[i].x ) and self.Polygon[i].x or x2 - y1 = ( y1 > self.Polygon[i].y ) and self.Polygon[i].y or y1 - y2 = ( y2 < self.Polygon[i].y ) and self.Polygon[i].y or y2 - - end - - return { x1 = x1, y1 = y1, x2 = x2, y2 = y2 } -end - - - - - ---- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- @type ZONE_POLYGON --- @extends Core.Zone#ZONE_POLYGON_BASE -ZONE_POLYGON = { - ClassName="ZONE_POLYGON", - } - ---- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Wrapper.Group#GROUP} defined within the Mission Editor. --- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. --- @param #ZONE_POLYGON self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Group#GROUP ZoneGroup The GROUP waypoints as defined within the Mission Editor define the polygon shape. --- @return #ZONE_POLYGON self -function ZONE_POLYGON:New( ZoneName, ZoneGroup ) - - local GroupPoints = ZoneGroup:GetTaskRoute() - - local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) ) - self:F( { ZoneName, ZoneGroup, self.Polygon } ) - - return self -end - ---- This module contains the DATABASE class, managing the database of mission objects. --- --- ==== --- --- 1) @{Core.Database#DATABASE} class, extends @{Core.Base#BASE} --- =================================================== --- Mission designers can use the DATABASE class to refer to: --- --- * UNITS --- * GROUPS --- * CLIENTS --- * AIRPORTS --- * PLAYERSJOINED --- * PLAYERS --- --- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor. --- --- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE. --- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required. --- --- 1.1) DATABASE iterators --- ----------------------- --- You can iterate the database with the available iterator methods. --- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the DATABASE: --- --- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE. --- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE. --- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE. --- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE. --- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE. --- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE. --- --- === --- --- @module Database --- @author FlightControl - ---- DATABASE class --- @type DATABASE --- @extends Core.Base#BASE -DATABASE = { - ClassName = "DATABASE", - Templates = { - Units = {}, - Groups = {}, - ClientsByName = {}, - ClientsByID = {}, - }, - UNITS = {}, - STATICS = {}, - GROUPS = {}, - PLAYERS = {}, - PLAYERSJOINED = {}, - CLIENTS = {}, - AIRBASES = {}, - NavPoints = {}, -} - -local _DATABASECoalition = - { - [1] = "Red", - [2] = "Blue", - } - -local _DATABASECategory = - { - ["plane"] = Unit.Category.AIRPLANE, - ["helicopter"] = Unit.Category.HELICOPTER, - ["vehicle"] = Unit.Category.GROUND_UNIT, - ["ship"] = Unit.Category.SHIP, - ["static"] = Unit.Category.STRUCTURE, - } - - ---- Creates a new DATABASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #DATABASE self --- @return #DATABASE --- @usage --- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. --- DBObject = DATABASE:New() -function DATABASE:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - _EVENTDISPATCHER:OnBirth( self._EventOnBirth, self ) - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - - - -- Follow alive players and clients - _EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self ) - _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self ) - - self:_RegisterTemplates() - self:_RegisterGroupsAndUnits() - self:_RegisterClients() - self:_RegisterStatics() - self:_RegisterPlayers() - self:_RegisterAirbases() - - return self -end - ---- Finds a Unit based on the Unit Name. --- @param #DATABASE self --- @param #string UnitName --- @return Wrapper.Unit#UNIT The found Unit. -function DATABASE:FindUnit( UnitName ) - - local UnitFound = self.UNITS[UnitName] - return UnitFound -end - - ---- Adds a Unit based on the Unit Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddUnit( DCSUnitName ) - - if not self.UNITS[DCSUnitName] then - local UnitRegister = UNIT:Register( DCSUnitName ) - self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) - end - - return self.UNITS[DCSUnitName] -end - - ---- Deletes a Unit from the DATABASE based on the Unit Name. --- @param #DATABASE self -function DATABASE:DeleteUnit( DCSUnitName ) - - --self.UNITS[DCSUnitName] = nil -end - ---- Adds a Static based on the Static Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddStatic( DCSStaticName ) - - if not self.STATICS[DCSStaticName] then - self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName ) - end -end - - ---- Deletes a Static from the DATABASE based on the Static Name. --- @param #DATABASE self -function DATABASE:DeleteStatic( DCSStaticName ) - - --self.STATICS[DCSStaticName] = nil -end - ---- Finds a STATIC based on the StaticName. --- @param #DATABASE self --- @param #string StaticName --- @return Wrapper.Static#STATIC The found STATIC. -function DATABASE:FindStatic( StaticName ) - - local StaticFound = self.STATICS[StaticName] - return StaticFound -end - ---- Adds a Airbase based on the Airbase Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddAirbase( DCSAirbaseName ) - - if not self.AIRBASES[DCSAirbaseName] then - self.AIRBASES[DCSAirbaseName] = AIRBASE:Register( DCSAirbaseName ) - end -end - - ---- Deletes a Airbase from the DATABASE based on the Airbase Name. --- @param #DATABASE self -function DATABASE:DeleteAirbase( DCSAirbaseName ) - - --self.AIRBASES[DCSAirbaseName] = nil -end - ---- Finds a AIRBASE based on the AirbaseName. --- @param #DATABASE self --- @param #string AirbaseName --- @return Wrapper.Airbase#AIRBASE The found AIRBASE. -function DATABASE:FindAirbase( AirbaseName ) - - local AirbaseFound = self.AIRBASES[AirbaseName] - return AirbaseFound -end - - ---- Finds a CLIENT based on the ClientName. --- @param #DATABASE self --- @param #string ClientName --- @return Wrapper.Client#CLIENT The found CLIENT. -function DATABASE:FindClient( ClientName ) - - local ClientFound = self.CLIENTS[ClientName] - return ClientFound -end - - ---- Adds a CLIENT based on the ClientName in the DATABASE. --- @param #DATABASE self -function DATABASE:AddClient( ClientName ) - - if not self.CLIENTS[ClientName] then - self.CLIENTS[ClientName] = CLIENT:Register( ClientName ) - end - - return self.CLIENTS[ClientName] -end - - ---- Finds a GROUP based on the GroupName. --- @param #DATABASE self --- @param #string GroupName --- @return Wrapper.Group#GROUP The found GROUP. -function DATABASE:FindGroup( GroupName ) - - local GroupFound = self.GROUPS[GroupName] - return GroupFound -end - - ---- Adds a GROUP based on the GroupName in the DATABASE. --- @param #DATABASE self -function DATABASE:AddGroup( GroupName ) - - if not self.GROUPS[GroupName] then - self.GROUPS[GroupName] = GROUP:Register( GroupName ) - end - - return self.GROUPS[GroupName] -end - ---- Adds a player based on the Player Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddPlayer( UnitName, PlayerName ) - - if PlayerName then - self:E( { "Add player for unit:", UnitName, PlayerName } ) - self.PLAYERS[PlayerName] = self:FindUnit( UnitName ) - self.PLAYERSJOINED[PlayerName] = PlayerName - end -end - ---- Deletes a player from the DATABASE based on the Player Name. --- @param #DATABASE self -function DATABASE:DeletePlayer( PlayerName ) - - if PlayerName then - self:E( { "Clean player:", PlayerName } ) - self.PLAYERS[PlayerName] = nil - end -end - - ---- Instantiate new Groups within the DCSRTE. --- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined: --- SpawnCountryID, SpawnCategoryID --- This method is used by the SPAWN class. --- @param #DATABASE self --- @param #table SpawnTemplate --- @return #DATABASE self -function DATABASE:Spawn( SpawnTemplate ) - self:F( SpawnTemplate.name ) - - self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) - - -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. - local SpawnCoalitionID = SpawnTemplate.CoalitionID - local SpawnCountryID = SpawnTemplate.CountryID - local SpawnCategoryID = SpawnTemplate.CategoryID - - -- Nullify - SpawnTemplate.CoalitionID = nil - SpawnTemplate.CountryID = nil - SpawnTemplate.CategoryID = nil - - self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) - - self:T3( SpawnTemplate ) - coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) - - -- Restore - SpawnTemplate.CoalitionID = SpawnCoalitionID - SpawnTemplate.CountryID = SpawnCountryID - SpawnTemplate.CategoryID = SpawnCategoryID - - local SpawnGroup = self:AddGroup( SpawnTemplate.name ) - return SpawnGroup -end - ---- Set a status to a Group within the Database, this to check crossing events for example. -function DATABASE:SetStatusGroup( GroupName, Status ) - self:F2( Status ) - - self.Templates.Groups[GroupName].Status = Status -end - ---- Get a status to a Group within the Database, this to check crossing events for example. -function DATABASE:GetStatusGroup( GroupName ) - self:F2( Status ) - - if self.Templates.Groups[GroupName] then - return self.Templates.Groups[GroupName].Status - else - return "" - end -end - ---- Private method that registers new Group Templates within the DATABASE Object. --- @param #DATABASE self --- @param #table GroupTemplate --- @return #DATABASE self -function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID ) - - local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name) - - local TraceTable = {} - - if not self.Templates.Groups[GroupTemplateName] then - self.Templates.Groups[GroupTemplateName] = {} - self.Templates.Groups[GroupTemplateName].Status = nil - end - - -- Delete the spans from the route, it is not needed and takes memory. - if GroupTemplate.route and GroupTemplate.route.spans then - GroupTemplate.route.spans = nil - end - - GroupTemplate.CategoryID = CategoryID - GroupTemplate.CoalitionID = CoalitionID - GroupTemplate.CountryID = CountryID - - self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName - self.Templates.Groups[GroupTemplateName].Template = GroupTemplate - self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId - self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units - self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units - self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID - self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID - self.Templates.Groups[GroupTemplateName].CountryID = CountryID - - - TraceTable[#TraceTable+1] = "Group" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID - - TraceTable[#TraceTable+1] = "Units" - - for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do - - UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name) - - self.Templates.Units[UnitTemplate.name] = {} - self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name - self.Templates.Units[UnitTemplate.name].Template = UnitTemplate - self.Templates.Units[UnitTemplate.name].GroupName = GroupTemplateName - self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate - self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId - self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID - self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID - self.Templates.Units[UnitTemplate.name].CountryID = CountryID - - if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then - self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate - self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID - self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID - self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID - self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate - end - - TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName - end - - self:E( TraceTable ) -end - -function DATABASE:GetGroupTemplate( GroupName ) - local GroupTemplate = self.Templates.Groups[GroupName].Template - GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID - GroupTemplate.SpawnCategoryID = self.Templates.Groups[GroupName].CategoryID - GroupTemplate.SpawnCountryID = self.Templates.Groups[GroupName].CountryID - return GroupTemplate -end - -function DATABASE:GetGroupNameFromUnitName( UnitName ) - return self.Templates.Units[UnitName].GroupName -end - -function DATABASE:GetGroupTemplateFromUnitName( UnitName ) - return self.Templates.Units[UnitName].GroupTemplate -end - -function DATABASE:GetCoalitionFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CoalitionID -end - -function DATABASE:GetCategoryFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CategoryID -end - -function DATABASE:GetCountryFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CountryID -end - ---- Airbase - -function DATABASE:GetCoalitionFromAirbase( AirbaseName ) - return self.AIRBASES[AirbaseName]:GetCoalition() -end - -function DATABASE:GetCategoryFromAirbase( AirbaseName ) - return self.AIRBASES[AirbaseName]:GetCategory() -end - - - ---- Private method that registers all alive players in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterPlayers() - - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for UnitId, UnitData in pairs( CoalitionData ) do - self:T3( { "UnitData:", UnitData } ) - if UnitData and UnitData:isExist() then - local UnitName = UnitData:getName() - local PlayerName = UnitData:getPlayerName() - if not self.PLAYERS[PlayerName] then - self:E( { "Add player for unit:", UnitName, PlayerName } ) - self:AddPlayer( UnitName, PlayerName ) - end - end - end - end - - return self -end - - ---- Private method that registers all Groups and Units within in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterGroupsAndUnits() - - local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSGroupId, DCSGroup in pairs( CoalitionData ) do - - if DCSGroup:isExist() then - local DCSGroupName = DCSGroup:getName() - - self:E( { "Register Group:", DCSGroupName } ) - self:AddGroup( DCSGroupName ) - - for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do - - local DCSUnitName = DCSUnit:getName() - self:E( { "Register Unit:", DCSUnitName } ) - self:AddUnit( DCSUnitName ) - end - else - self:E( { "Group does not exist: ", DCSGroup } ) - end - - end - end - - return self -end - ---- Private method that registers all Units of skill Client or Player within in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterClients() - - for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do - self:E( { "Register Client:", ClientName } ) - self:AddClient( ClientName ) - end - - return self -end - ---- @param #DATABASE self -function DATABASE:_RegisterStatics() - - local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSStaticId, DCSStatic in pairs( CoalitionData ) do - - if DCSStatic:isExist() then - local DCSStaticName = DCSStatic:getName() - - self:E( { "Register Static:", DCSStaticName } ) - self:AddStatic( DCSStaticName ) - else - self:E( { "Static does not exist: ", DCSStatic } ) - end - end - end - - return self -end - ---- @param #DATABASE self -function DATABASE:_RegisterAirbases() - - local CoalitionsData = { AirbasesRed = coalition.getAirbases( coalition.side.RED ), AirbasesBlue = coalition.getAirbases( coalition.side.BLUE ), AirbasesNeutral = coalition.getAirbases( coalition.side.NEUTRAL ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSAirbaseId, DCSAirbase in pairs( CoalitionData ) do - - local DCSAirbaseName = DCSAirbase:getName() - - self:E( { "Register Airbase:", DCSAirbaseName } ) - self:AddAirbase( DCSAirbaseName ) - end - end - - return self -end - - ---- Events - ---- Handles the OnBirth event for the alive units set. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnBirth( Event ) - self:F2( { Event } ) - - if Event.IniDCSUnit then - self:AddUnit( Event.IniDCSUnitName ) - self:AddGroup( Event.IniDCSGroupName ) - self:_EventOnPlayerEnterUnit( Event ) - end -end - - ---- Handles the OnDead or OnCrash event for alive units set. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnDeadOrCrash( Event ) - self:F2( { Event } ) - - if Event.IniDCSUnit then - if self.UNITS[Event.IniDCSUnitName] then - self:DeleteUnit( Event.IniDCSUnitName ) - -- add logic to correctly remove a group once all units are destroyed... - end - end -end - - ---- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnPlayerEnterUnit( Event ) - self:F2( { Event } ) - - if Event.IniUnit then - local PlayerName = Event.IniUnit:GetPlayerName() - if not self.PLAYERS[PlayerName] then - self:AddPlayer( Event.IniUnitName, PlayerName ) - end - end -end - - ---- Handles the OnPlayerLeaveUnit event to clean the active players table. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnPlayerLeaveUnit( Event ) - self:F2( { Event } ) - - if Event.IniUnit then - local PlayerName = Event.IniUnit:GetPlayerName() - if self.PLAYERS[PlayerName] then - self:DeletePlayer( PlayerName ) - end - end -end - ---- Iterators - ---- Iterate the DATABASE and call an iterator function for the given set, providing the Object for each element within the set and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive player in the database. --- @return #DATABASE self -function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set ) - self:F2( arg ) - - local function CoRoutine() - local Count = 0 - for ObjectID, Object in pairs( Set ) do - self:T2( Object ) - IteratorFunction( Object, unpack( arg ) ) - Count = Count + 1 --- if Count % 100 == 0 then --- coroutine.yield( false ) --- end - end - return true - end - --- local co = coroutine.create( CoRoutine ) - local co = CoRoutine - - local function Schedule() - --- local status, res = coroutine.resume( co ) - local status, res = co() - self:T3( { status, res } ) - - if status == false then - error( res ) - end - if res == false then - return true -- resume next time the loop - end - if FinalizeFunction then - FinalizeFunction( unpack( arg ) ) - end - return false - end - - local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter. --- @return #DATABASE self -function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS ) - - return self -end - ---- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter. --- @return #DATABASE self -function DATABASE:ForEachGroup( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.GROUPS ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an player in the database. The function needs to accept the player name. --- @return #DATABASE self -function DATABASE:ForEachPlayer( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.PLAYERS ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter. --- @return #DATABASE self -function DATABASE:ForEachPlayerJoined( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.PLAYERSJOINED ) - - return self -end - ---- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter. --- @return #DATABASE self -function DATABASE:ForEachClient( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.CLIENTS ) - - return self -end - - -function DATABASE:_RegisterTemplates() - self:F2() - - self.Navpoints = {} - self.UNITS = {} - --Build routines.db.units and self.Navpoints - for CoalitionName, coa_data in pairs(env.mission.coalition) do - - if (CoalitionName == 'red' or CoalitionName == 'blue') and type(coa_data) == 'table' then - --self.Units[coa_name] = {} - - ---------------------------------------------- - -- build nav points DB - self.Navpoints[CoalitionName] = {} - if coa_data.nav_points then --navpoints - for nav_ind, nav_data in pairs(coa_data.nav_points) do - - if type(nav_data) == 'table' then - self.Navpoints[CoalitionName][nav_ind] = routines.utils.deepCopy(nav_data) - - self.Navpoints[CoalitionName][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. - self.Navpoints[CoalitionName][nav_ind]['point'] = {} -- point is used by SSE, support it. - self.Navpoints[CoalitionName][nav_ind]['point']['x'] = nav_data.x - self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0 - self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y - end - end - end - ------------------------------------------------- - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - - local CountryName = string.upper(cntry_data.name) - --self.Units[coa_name][countryName] = {} - --self.Units[coa_name][countryName]["countryId"] = cntry_data.id - - if type(cntry_data) == 'table' then --just making sure - - for obj_type_name, obj_type_data in pairs(cntry_data) do - - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check - - local CategoryName = obj_type_name - - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - - --self.Units[coa_name][countryName][category] = {} - - for group_num, GroupTemplate in pairs(obj_type_data.group) do - - if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group - self:_RegisterTemplate( - GroupTemplate, - coalition.side[string.upper(CoalitionName)], - _DATABASECategory[string.lower(CategoryName)], - country.id[string.upper(CountryName)] - ) - end --if GroupTemplate and GroupTemplate.units then - end --for group_num, GroupTemplate in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --if type(cntry_data) == 'table' then - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - - return self -end - - - - ---- This module contains the SET classes. --- --- === --- --- 1) @{Core.Set#SET_BASE} class, extends @{Core.Base#BASE} --- ============================================== --- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. --- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. --- In this way, large loops can be done while not blocking the simulator main processing loop. --- The default **"yield interval"** is after 10 objects processed. --- The default **"time interval"** is after 0.001 seconds. --- --- 1.1) Add or remove objects from the SET --- --------------------------------------- --- Some key core functions are @{Core.Set#SET_BASE.Add} and @{Core.Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. --- --- 1.2) Define the SET iterator **"yield interval"** and the **"time interval"** --- ----------------------------------------------------------------------------- --- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetInteratorIntervals} method. --- You can set the **"yield interval"**, and the **"time interval"**. (See above). --- --- === --- --- 2) @{Core.Set#SET_GROUP} class, extends @{Core.Set#SET_BASE} --- ================================================== --- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Starting with certain prefix strings. --- --- 2.1) SET_GROUP construction method: --- ----------------------------------- --- Create a new SET_GROUP object with the @{#SET_GROUP.New} method: --- --- * @{#SET_GROUP.New}: Creates a new SET_GROUP object. --- --- 2.2) Add or Remove GROUP(s) from SET_GROUP: --- ------------------------------------------- --- GROUPS can be added and removed using the @{Core.Set#SET_GROUP.AddGroupsByName} and @{Core.Set#SET_GROUP.RemoveGroupsByName} respectively. --- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_GROUP. --- --- 2.3) SET_GROUP filter criteria: --- ------------------------------- --- You can set filter criteria to define the set of groups within the SET_GROUP. --- Filter criteria are defined by: --- --- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s). --- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies). --- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies). --- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: --- --- * @{#SET_GROUP.FilterStart}: Starts the filtering of the groups within the SET_GROUP and add or remove GROUP objects **dynamically**. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. --- --- 2.4) SET_GROUP iterators: --- ------------------------- --- Once the filters have been defined and the SET_GROUP has been built, you can iterate the SET_GROUP with the available iterator methods. --- The iterator methods will walk the SET_GROUP set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_GROUP: --- --- * @{#SET_GROUP.ForEachGroup}: Calls a function for each alive group it finds within the SET_GROUP. --- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupPartlyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- --- ==== --- --- 3) @{Core.Set#SET_UNIT} class, extends @{Core.Set#SET_BASE} --- =================================================== --- Mission designers can use the @{Core.Set#SET_UNIT} class to build sets of units belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Unit types --- * Starting with certain prefix strings. --- --- 3.1) SET_UNIT construction method: --- ---------------------------------- --- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: --- --- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. --- --- 3.2) Add or Remove UNIT(s) from SET_UNIT: --- ----------------------------------------- --- UNITs can be added and removed using the @{Core.Set#SET_UNIT.AddUnitsByName} and @{Core.Set#SET_UNIT.RemoveUnitsByName} respectively. --- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. --- --- 3.3) SET_UNIT filter criteria: --- ------------------------------ --- You can set filter criteria to define the set of units within the SET_UNIT. --- Filter criteria are defined by: --- --- * @{#SET_UNIT.FilterCoalitions}: Builds the SET_UNIT with the units belonging to the coalition(s). --- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). --- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). --- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). --- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: --- --- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. --- --- 3.4) SET_UNIT iterators: --- ------------------------ --- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. --- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_UNIT: --- --- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. --- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- --- Planned iterators methods in development are (so these are not yet available): --- --- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. --- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- --- === --- --- 4) @{Core.Set#SET_CLIENT} class, extends @{Core.Set#SET_BASE} --- =================================================== --- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Client types --- * Starting with certain prefix strings. --- --- 4.1) SET_CLIENT construction method: --- ---------------------------------- --- Create a new SET_CLIENT object with the @{#SET_CLIENT.New} method: --- --- * @{#SET_CLIENT.New}: Creates a new SET_CLIENT object. --- --- 4.2) Add or Remove CLIENT(s) from SET_CLIENT: --- ----------------------------------------- --- CLIENTs can be added and removed using the @{Core.Set#SET_CLIENT.AddClientsByName} and @{Core.Set#SET_CLIENT.RemoveClientsByName} respectively. --- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. --- --- 4.3) SET_CLIENT filter criteria: --- ------------------------------ --- You can set filter criteria to define the set of clients within the SET_CLIENT. --- Filter criteria are defined by: --- --- * @{#SET_CLIENT.FilterCoalitions}: Builds the SET_CLIENT with the clients belonging to the coalition(s). --- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies). --- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s). --- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). --- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: --- --- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients within the SET_CLIENT. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. --- --- 4.4) SET_CLIENT iterators: --- ------------------------ --- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. --- The iterator methods will walk the SET_CLIENT set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_CLIENT: --- --- * @{#SET_CLIENT.ForEachClient}: Calls a function for each alive client it finds within the SET_CLIENT. --- --- ==== --- --- 5) @{Core.Set#SET_AIRBASE} class, extends @{Core.Set#SET_BASE} --- ==================================================== --- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: --- --- * Coalitions --- --- 5.1) SET_AIRBASE construction --- ----------------------------- --- Create a new SET_AIRBASE object with the @{#SET_AIRBASE.New} method: --- --- * @{#SET_AIRBASE.New}: Creates a new SET_AIRBASE object. --- --- 5.2) Add or Remove AIRBASEs from SET_AIRBASE --- -------------------------------------------- --- AIRBASEs can be added and removed using the @{Core.Set#SET_AIRBASE.AddAirbasesByName} and @{Core.Set#SET_AIRBASE.RemoveAirbasesByName} respectively. --- These methods take a single AIRBASE name or an array of AIRBASE names to be added or removed from SET_AIRBASE. --- --- 5.3) SET_AIRBASE filter criteria --- -------------------------------- --- You can set filter criteria to define the set of clients within the SET_AIRBASE. --- Filter criteria are defined by: --- --- * @{#SET_AIRBASE.FilterCoalitions}: Builds the SET_AIRBASE with the airbases belonging to the coalition(s). --- --- Once the filter criteria have been set for the SET_AIRBASE, you can start filtering using: --- --- * @{#SET_AIRBASE.FilterStart}: Starts the filtering of the airbases within the SET_AIRBASE. --- --- 5.4) SET_AIRBASE iterators: --- --------------------------- --- Once the filters have been defined and the SET_AIRBASE has been built, you can iterate the SET_AIRBASE with the available iterator methods. --- The iterator methods will walk the SET_AIRBASE set, and call for each airbase within the set a function that you provide. --- The following iterator methods are currently available within the SET_AIRBASE: --- --- * @{#SET_AIRBASE.ForEachAirbase}: Calls a function for each airbase it finds within the SET_AIRBASE. --- --- ==== --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Contributions: --- --- --- @module Set - - ---- SET_BASE class --- @type SET_BASE --- @field #table Filter --- @field #table Set --- @field #table List --- @field Core.Scheduler#SCHEDULER CallScheduler --- @extends Core.Base#BASE -SET_BASE = { - ClassName = "SET_BASE", - Filter = {}, - Set = {}, - List = {}, -} - ---- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_BASE self --- @return #SET_BASE --- @usage --- -- Define a new SET_BASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. --- DBObject = SET_BASE:New() -function SET_BASE:New( Database ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE - - self.Database = Database - - self.YieldInterval = 10 - self.TimeInterval = 0.001 - - self.List = {} - self.List.__index = self.List - self.List = setmetatable( { Count = 0 }, self.List ) - - self.CallScheduler = SCHEDULER:New( self ) - - return self -end - ---- Finds an @{Core.Base#BASE} object based on the object Name. --- @param #SET_BASE self --- @param #string ObjectName --- @return Core.Base#BASE The Object found. -function SET_BASE:_Find( ObjectName ) - - local ObjectFound = self.Set[ObjectName] - return ObjectFound -end - - ---- Gets the Set. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:GetSet() - self:F2() - - return self.Set -end - ---- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index. --- @param #SET_BASE self --- @param #string ObjectName --- @param Core.Base#BASE Object --- @return Core.Base#BASE The added BASE Object. -function SET_BASE:Add( ObjectName, Object ) - self:F2( ObjectName ) - - local t = { _ = Object } - - if self.List.last then - self.List.last._next = t - t._prev = self.List.last - self.List.last = t - else - -- this is the first node - self.List.first = t - self.List.last = t - end - - self.List.Count = self.List.Count + 1 - - self.Set[ObjectName] = t._ - -end - ---- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index. --- @param #SET_BASE self --- @param Wrapper.Object#OBJECT Object --- @return Core.Base#BASE The added BASE Object. -function SET_BASE:AddObject( Object ) - self:F2( Object.ObjectName ) - - self:T( Object.UnitName ) - self:T( Object.ObjectName ) - self:Add( Object.ObjectName, Object ) - -end - - - ---- Removes a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. --- @param #SET_BASE self --- @param #string ObjectName -function SET_BASE:Remove( ObjectName ) - self:F( ObjectName ) - - local t = self.Set[ObjectName] - - self:E( { ObjectName, t } ) - - if t then - if t._next then - if t._prev then - t._next._prev = t._prev - t._prev._next = t._next - else - -- this was the first node - t._next._prev = nil - self.List._first = t._next - end - elseif t._prev then - -- this was the last node - t._prev._next = nil - self.List._last = t._prev - else - -- this was the only node - self.List._first = nil - self.List._last = nil - end - - t._next = nil - t._prev = nil - self.List.Count = self.List.Count - 1 - - self.Set[ObjectName] = nil - end - -end - ---- Gets a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. --- @param #SET_BASE self --- @param #string ObjectName --- @return Core.Base#BASE -function SET_BASE:Get( ObjectName ) - self:F( ObjectName ) - - local t = self.Set[ObjectName] - - self:T3( { ObjectName, t } ) - - return t - -end - ---- Retrieves the amount of objects in the @{Core.Set#SET_BASE} and derived classes. --- @param #SET_BASE self --- @return #number Count -function SET_BASE:Count() - - return self.List.Count -end - - - ---- Copies the Filter criteria from a given Set (for rebuilding a new Set based on an existing Set). --- @param #SET_BASE self --- @param #SET_BASE BaseSet --- @return #SET_BASE -function SET_BASE:SetDatabase( BaseSet ) - - -- Copy the filter criteria of the BaseSet - local OtherFilter = routines.utils.deepCopy( BaseSet.Filter ) - self.Filter = OtherFilter - - -- Now base the new Set on the BaseSet - self.Database = BaseSet:GetSet() - return self -end - - - ---- Define the SET iterator **"yield interval"** and the **"time interval"**. --- @param #SET_BASE self --- @param #number YieldInterval Sets the frequency when the iterator loop will yield after the number of objects processed. The default frequency is 10 objects processed. --- @param #number TimeInterval Sets the time in seconds when the main logic will resume the iterator loop. The default time is 0.001 seconds. --- @return #SET_BASE self -function SET_BASE:SetIteratorIntervals( YieldInterval, TimeInterval ) - - self.YieldInterval = YieldInterval - self.TimeInterval = TimeInterval - - return self -end - - ---- Filters for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:FilterOnce() - - for ObjectName, Object in pairs( self.Database ) do - - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - end - end - - return self -end - ---- Starts the filtering for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:_FilterStart() - - for ObjectName, Object in pairs( self.Database ) do - - if self:IsIncludeObject( Object ) then - self:E( { "Adding Object:", ObjectName } ) - self:Add( ObjectName, Object ) - end - end - - _EVENTDISPATCHER:OnBirth( self._EventOnBirth, self ) - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - - -- Follow alive players and clients - _EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self ) - _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self ) - - - return self -end - ---- Stops the filtering for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:FilterStop() - - _EVENTDISPATCHER:OnBirthRemove( self ) - _EVENTDISPATCHER:OnDeadRemove( self ) - _EVENTDISPATCHER:OnCrashRemove( self ) - - return self -end - ---- Iterate the SET_BASE while identifying the nearest object from a @{Core.Point#POINT_VEC2}. --- @param #SET_BASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set. --- @return Core.Base#BASE The closest object. -function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ) - self:F2( PointVec2 ) - - local NearestObject = nil - local ClosestDistance = nil - - for ObjectID, ObjectData in pairs( self.Set ) do - if NearestObject == nil then - NearestObject = ObjectData - ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) - else - local Distance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) - if Distance < ClosestDistance then - NearestObject = ObjectData - ClosestDistance = Distance - end - end - end - - return NearestObject -end - - - ------ Private method that registers all alive players in the mission. ----- @param #SET_BASE self ----- @return #SET_BASE self ---function SET_BASE:_RegisterPlayers() --- --- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } --- for CoalitionId, CoalitionData in pairs( CoalitionsData ) do --- for UnitId, UnitData in pairs( CoalitionData ) do --- self:T3( { "UnitData:", UnitData } ) --- if UnitData and UnitData:isExist() then --- local UnitName = UnitData:getName() --- if not self.PlayersAlive[UnitName] then --- self:E( { "Add player for unit:", UnitName, UnitData:getPlayerName() } ) --- self.PlayersAlive[UnitName] = UnitData:getPlayerName() --- end --- end --- end --- end --- --- return self ---end - ---- Events - ---- Handles the OnBirth event for the Set. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnBirth( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:AddInDatabase( Event ) - self:T3( ObjectName, Object ) - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - --self:_EventOnPlayerEnterUnit( Event ) - end - end -end - ---- Handles the OnDead or OnCrash event for alive units set. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:FindInDatabase( Event ) - if ObjectName and Object ~= nil then - self:Remove( ObjectName ) - end - end -end - ---- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnPlayerEnterUnit( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:AddInDatabase( Event ) - self:T3( ObjectName, Object ) - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - --self:_EventOnPlayerEnterUnit( Event ) - end - end -end - ---- Handles the OnPlayerLeaveUnit event to clean the active players table. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnPlayerLeaveUnit( Event ) - self:F3( { Event } ) - - local ObjectName = Event.IniDCSUnit - if Event.IniDCSUnit then - if Event.IniDCSGroup then - local GroupUnits = Event.IniDCSGroup:getUnits() - local PlayerCount = 0 - for _, DCSUnit in pairs( GroupUnits ) do - if DCSUnit ~= Event.IniDCSUnit then - if DCSUnit:getPlayer() ~= nil then - PlayerCount = PlayerCount + 1 - end - end - end - self:E(PlayerCount) - if PlayerCount == 0 then - self:Remove( Event.IniDCSGroupName ) - end - end - end -end - --- Iterators - ---- Iterate the SET_BASE and derived classes and call an iterator function for the given SET_BASE, providing the Object for each element within the set and optional parameters. --- @param #SET_BASE self --- @param #function IteratorFunction The function that will be called. --- @return #SET_BASE self -function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArguments ) - self:F3( arg ) - - Set = Set or self:GetSet() - arg = arg or {} - - local function CoRoutine() - local Count = 0 - for ObjectID, ObjectData in pairs( Set ) do - local Object = ObjectData - self:T3( Object ) - if Function then - if Function( unpack( FunctionArguments ), Object ) == true then - IteratorFunction( Object, unpack( arg ) ) - end - else - IteratorFunction( Object, unpack( arg ) ) - end - Count = Count + 1 --- if Count % self.YieldInterval == 0 then --- coroutine.yield( false ) --- end - end - return true - end - --- local co = coroutine.create( CoRoutine ) - local co = CoRoutine - - local function Schedule() - --- local status, res = coroutine.resume( co ) - local status, res = co() - self:T3( { status, res } ) - - if status == false then - error( res ) - end - if res == false then - return true -- resume next time the loop - end - - return false - end - - self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) - - return self -end - - ------ Iterate the SET_BASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.DCSUnitsAlive ) --- --- return self ---end --- ------ Iterate the SET_BASE and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachPlayer( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_BASE and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachClient( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- Decides whether to include the Object --- @param #SET_BASE self --- @param #table Object --- @return #SET_BASE self -function SET_BASE:IsIncludeObject( Object ) - self:F3( Object ) - - return true -end - ---- Flushes the current SET_BASE contents in the log ... (for debugging reasons). --- @param #SET_BASE self --- @return #string A string with the names of the objects. -function SET_BASE:Flush() - self:F3() - - local ObjectNames = "" - for ObjectName, Object in pairs( self.Set ) do - ObjectNames = ObjectNames .. ObjectName .. ", " - end - self:E( { "Objects in Set:", ObjectNames } ) - - return ObjectNames -end - --- SET_GROUP - ---- SET_GROUP class --- @type SET_GROUP --- @extends #SET_BASE -SET_GROUP = { - ClassName = "SET_GROUP", - Filter = { - Coalitions = nil, - Categories = nil, - Countries = nil, - GroupPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Group.Category.AIRPLANE, - helicopter = Group.Category.HELICOPTER, - ground = Group.Category.GROUND_UNIT, - ship = Group.Category.SHIP, - structure = Group.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_GROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_GROUP self --- @return #SET_GROUP --- @usage --- -- Define a new SET_GROUP Object. This DBObject will contain a reference to all alive GROUPS. --- DBObject = SET_GROUP:New() -function SET_GROUP:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) - - return self -end - ---- Add GROUP(s) to SET_GROUP. --- @param Core.Set#SET_GROUP self --- @param #string AddGroupNames A single name or an array of GROUP names. --- @return self -function SET_GROUP:AddGroupsByName( AddGroupNames ) - - local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames } - - for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do - self:Add( AddGroupName, GROUP:FindByName( AddGroupName ) ) - end - - return self -end - ---- Remove GROUP(s) from SET_GROUP. --- @param Core.Set#SET_GROUP self --- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names. --- @return self -function SET_GROUP:RemoveGroupsByName( RemoveGroupNames ) - - local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames } - - for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do - self:Remove( RemoveGroupName.GroupName ) - end - - return self -end - - - - ---- Finds a Group based on the Group Name. --- @param #SET_GROUP self --- @param #string GroupName --- @return Wrapper.Group#GROUP The found Group. -function SET_GROUP:FindGroup( GroupName ) - - local GroupFound = self.Set[GroupName] - return GroupFound -end - - - ---- Builds a set of groups of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_GROUP self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_GROUP self -function SET_GROUP:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of groups out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_GROUP self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_GROUP self -function SET_GROUP:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - ---- Builds a set of groups of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_GROUP self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_GROUP self -function SET_GROUP:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of groups of defined GROUP prefixes. --- All the groups starting with the given prefixes will be included within the set. --- @param #SET_GROUP self --- @param #string Prefixes The prefix of which the group name starts with. --- @return #SET_GROUP self -function SET_GROUP:FilterPrefixes( Prefixes ) - if not self.Filter.GroupPrefixes then - self.Filter.GroupPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.GroupPrefixes[Prefix] = Prefix - end - return self -end - - ---- Starts the filtering. --- @param #SET_GROUP self --- @return #SET_GROUP self -function SET_GROUP:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_GROUP self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the GROUP --- @return #table The GROUP -function SET_GROUP:AddInDatabase( Event ) - self:F3( { Event } ) - - if not self.Database[Event.IniDCSGroupName] then - self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName ) - self:T3( self.Database[Event.IniDCSGroupName] ) - end - - return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_GROUP self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the GROUP --- @return #table The GROUP -function SET_GROUP:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. --- @param #SET_GROUP self --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroup( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupCompletelyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsCompletelyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupPartlyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsPartlyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - - ------ Iterate the SET_GROUP and call an interator function for each **alive** player, providing the Group of the player and optional parameters. ----- @param #SET_GROUP self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. ----- @return #SET_GROUP self ---function SET_GROUP:ForEachPlayer( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_GROUP and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_GROUP self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. ----- @return #SET_GROUP self ---function SET_GROUP:ForEachClient( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- --- @param #SET_GROUP self --- @param Wrapper.Group#GROUP MooseGroup --- @return #SET_GROUP self -function SET_GROUP:IsIncludeObject( MooseGroup ) - self:F2( MooseGroup ) - local MooseGroupInclude = true - - if self.Filter.Coalitions then - local MooseGroupCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MooseGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MooseGroup:GetCoalition() then - MooseGroupCoalition = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCoalition - end - - if self.Filter.Categories then - local MooseGroupCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MooseGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MooseGroup:GetCategory() then - MooseGroupCategory = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCategory - end - - if self.Filter.Countries then - local MooseGroupCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MooseGroup:GetCountry(), CountryName } ) - if country.id[CountryName] == MooseGroup:GetCountry() then - MooseGroupCountry = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCountry - end - - if self.Filter.GroupPrefixes then - local MooseGroupPrefix = false - for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do - self:T3( { "Prefix:", string.find( MooseGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) - if string.find( MooseGroup:GetName(), GroupPrefix, 1 ) then - MooseGroupPrefix = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupPrefix - end - - self:T2( MooseGroupInclude ) - return MooseGroupInclude -end - ---- SET_UNIT class --- @type SET_UNIT --- @extends Core.Set#SET_BASE -SET_UNIT = { - ClassName = "SET_UNIT", - Units = {}, - Filter = { - Coalitions = nil, - Categories = nil, - Types = nil, - Countries = nil, - UnitPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Unit.Category.AIRPLANE, - helicopter = Unit.Category.HELICOPTER, - ground = Unit.Category.GROUND_UNIT, - ship = Unit.Category.SHIP, - structure = Unit.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_UNIT self --- @return #SET_UNIT --- @usage --- -- Define a new SET_UNIT Object. This DBObject will contain a reference to all alive Units. --- DBObject = SET_UNIT:New() -function SET_UNIT:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) - - return self -end - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnit A single UNIT. --- @return #SET_UNIT self -function SET_UNIT:AddUnit( AddUnit ) - self:F2( AddUnit:GetName() ) - - self:Add( AddUnit:GetName(), AddUnit ) - - return self -end - - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnitNames A single name or an array of UNIT names. --- @return #SET_UNIT self -function SET_UNIT:AddUnitsByName( AddUnitNames ) - - local AddUnitNamesArray = ( type( AddUnitNames ) == "table" ) and AddUnitNames or { AddUnitNames } - - self:T( AddUnitNamesArray ) - for AddUnitID, AddUnitName in pairs( AddUnitNamesArray ) do - self:Add( AddUnitName, UNIT:FindByName( AddUnitName ) ) - end - - return self -end - ---- Remove UNIT(s) from SET_UNIT. --- @param Core.Set#SET_UNIT self --- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names. --- @return self -function SET_UNIT:RemoveUnitsByName( RemoveUnitNames ) - - local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames } - - for RemoveUnitID, RemoveUnitName in pairs( RemoveUnitNamesArray ) do - self:Remove( RemoveUnitName ) - end - - return self -end - - ---- Finds a Unit based on the Unit Name. --- @param #SET_UNIT self --- @param #string UnitName --- @return Wrapper.Unit#UNIT The found Unit. -function SET_UNIT:FindUnit( UnitName ) - - local UnitFound = self.Set[UnitName] - return UnitFound -end - - - ---- Builds a set of units of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_UNIT self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_UNIT self -function SET_UNIT:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of units out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_UNIT self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_UNIT self -function SET_UNIT:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - - ---- Builds a set of units of defined unit types. --- Possible current types are those types known within DCS world. --- @param #SET_UNIT self --- @param #string Types Can take those type strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterTypes( Types ) - if not self.Filter.Types then - self.Filter.Types = {} - end - if type( Types ) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs( Types ) do - self.Filter.Types[Type] = Type - end - return self -end - - ---- Builds a set of units of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_UNIT self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of units of defined unit prefixes. --- All the units starting with the given prefixes will be included within the set. --- @param #SET_UNIT self --- @param #string Prefixes The prefix of which the unit name starts with. --- @return #SET_UNIT self -function SET_UNIT:FilterPrefixes( Prefixes ) - if not self.Filter.UnitPrefixes then - self.Filter.UnitPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.UnitPrefixes[Prefix] = Prefix - end - return self -end - ---- Builds a set of units having a radar of give types. --- All the units having a radar of a given type will be included within the set. --- @param #SET_UNIT self --- @param #table RadarTypes The radar types. --- @return #SET_UNIT self -function SET_UNIT:FilterHasRadar( RadarTypes ) - - self.Filter.RadarTypes = self.Filter.RadarTypes or {} - if type( RadarTypes ) ~= "table" then - RadarTypes = { RadarTypes } - end - for RadarTypeID, RadarType in pairs( RadarTypes ) do - self.Filter.RadarTypes[RadarType] = RadarType - end - return self -end - ---- Builds a set of SEADable units. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterHasSEAD() - - self.Filter.SEAD = true - return self -end - - - ---- Starts the filtering. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:AddInDatabase( Event ) - self:F3( { Event } ) - - if not self.Database[Event.IniDCSUnitName] then - self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) - self:T3( self.Database[Event.IniDCSUnitName] ) - end - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:FindInDatabase( Event ) - self:E( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } ) - - - return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName] -end - ---- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. --- @param #SET_UNIT self --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnit( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsCompletelyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Returns map of unit types. --- @param #SET_UNIT self --- @return #map<#string,#number> A map of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. -function SET_UNIT:GetUnitTypes() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = {} - - for UnitID, UnitData in pairs( self:GetSet() ) do - local TextUnit = UnitData -- Wrapper.Unit#UNIT - if TextUnit:IsAlive() then - local UnitType = TextUnit:GetTypeName() - - if not UnitTypes[UnitType] then - UnitTypes[UnitType] = 1 - else - UnitTypes[UnitType] = UnitTypes[UnitType] + 1 - end - end - end - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return UnitTypes -end - - ---- Returns a comma separated string of the unit types with a count in the @{Set}. --- @param #SET_UNIT self --- @return #string The unit types string -function SET_UNIT:GetUnitTypesText() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = self:GetUnitTypes() - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return table.concat( MT, ", " ) -end - ---- Returns map of unit threat levels. --- @param #SET_UNIT self --- @return #table. -function SET_UNIT:GetUnitThreatLevels() - self:F2() - - local UnitThreatLevels = {} - - for UnitID, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - if ThreatUnit:IsAlive() then - local UnitThreatLevel, UnitThreatLevelText = ThreatUnit:GetThreatLevel() - local ThreatUnitName = ThreatUnit:GetName() - - UnitThreatLevels[UnitThreatLevel] = UnitThreatLevels[UnitThreatLevel] or {} - UnitThreatLevels[UnitThreatLevel].UnitThreatLevelText = UnitThreatLevelText - UnitThreatLevels[UnitThreatLevel].Units = UnitThreatLevels[UnitThreatLevel].Units or {} - UnitThreatLevels[UnitThreatLevel].Units[ThreatUnitName] = ThreatUnit - end - end - - return UnitThreatLevels -end - ---- Calculate the maxium A2G threat level of the SET_UNIT. --- @param #SET_UNIT self -function SET_UNIT:CalculateThreatLevelA2G() - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - return MaxThreatLevelA2G - -end - - ---- Returns if the @{Set} has targets having a radar (of a given type). --- @param #SET_UNIT self --- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType --- @return #number The amount of radars in the Set with the given type -function SET_UNIT:HasRadar( RadarType ) - self:F2( RadarType ) - - local RadarCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSensorTest = UnitData -- Wrapper.Unit#UNIT - local HasSensors - if RadarType then - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType ) - else - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR ) - end - self:T3(HasSensors) - if HasSensors then - RadarCount = RadarCount + 1 - end - end - - return RadarCount -end - ---- Returns if the @{Set} has targets that can be SEADed. --- @param #SET_UNIT self --- @return #number The amount of SEADable units in the Set -function SET_UNIT:HasSEAD() - self:F2() - - local SEADCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSEAD = UnitData -- Wrapper.Unit#UNIT - if UnitSEAD:IsAlive() then - local UnitSEADAttributes = UnitSEAD:GetDesc().attributes - - local HasSEAD = UnitSEAD:HasSEAD() - - self:T3(HasSEAD) - if HasSEAD then - SEADCount = SEADCount + 1 - end - end - end - - return SEADCount -end - ---- Returns if the @{Set} has ground targets. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasGroundUnits() - self:F2() - - local GroundUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsGround() then - GroundUnitCount = GroundUnitCount + 1 - end - end - - return GroundUnitCount -end - ---- Returns if the @{Set} has friendly ground units. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasFriendlyUnits( FriendlyCoalition ) - self:F2() - - local FriendlyUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsFriendly( FriendlyCoalition ) then - FriendlyUnitCount = FriendlyUnitCount + 1 - end - end - - return FriendlyUnitCount -end - - - ------ Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachClient( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- --- @param #SET_UNIT self --- @param Wrapper.Unit#UNIT MUnit --- @return #SET_UNIT self -function SET_UNIT:IsIncludeObject( MUnit ) - self:F2( MUnit ) - local MUnitInclude = true - - if self.Filter.Coalitions then - local MUnitCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then - MUnitCoalition = true - end - end - MUnitInclude = MUnitInclude and MUnitCoalition - end - - if self.Filter.Categories then - local MUnitCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then - MUnitCategory = true - end - end - MUnitInclude = MUnitInclude and MUnitCategory - end - - if self.Filter.Types then - local MUnitType = false - for TypeID, TypeName in pairs( self.Filter.Types ) do - self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) - if TypeName == MUnit:GetTypeName() then - MUnitType = true - end - end - MUnitInclude = MUnitInclude and MUnitType - end - - if self.Filter.Countries then - local MUnitCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) - if country.id[CountryName] == MUnit:GetCountry() then - MUnitCountry = true - end - end - MUnitInclude = MUnitInclude and MUnitCountry - end - - if self.Filter.UnitPrefixes then - local MUnitPrefix = false - for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do - self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) - if string.find( MUnit:GetName(), UnitPrefix, 1 ) then - MUnitPrefix = true - end - end - MUnitInclude = MUnitInclude and MUnitPrefix - end - - if self.Filter.RadarTypes then - local MUnitRadar = false - for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do - self:T3( { "Radar:", RadarType } ) - if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then - if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability. - self:T3( "RADAR Found" ) - end - MUnitRadar = true - end - end - MUnitInclude = MUnitInclude and MUnitRadar - end - - if self.Filter.SEAD then - local MUnitSEAD = false - if MUnit:HasSEAD() == true then - self:T3( "SEAD Found" ) - MUnitSEAD = true - end - MUnitInclude = MUnitInclude and MUnitSEAD - end - - self:T2( MUnitInclude ) - return MUnitInclude -end - - ---- SET_CLIENT - ---- SET_CLIENT class --- @type SET_CLIENT --- @extends Core.Set#SET_BASE -SET_CLIENT = { - ClassName = "SET_CLIENT", - Clients = {}, - Filter = { - Coalitions = nil, - Categories = nil, - Types = nil, - Countries = nil, - ClientPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Unit.Category.AIRPLANE, - helicopter = Unit.Category.HELICOPTER, - ground = Unit.Category.GROUND_UNIT, - ship = Unit.Category.SHIP, - structure = Unit.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_CLIENT object, building a set of clients belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_CLIENT self --- @return #SET_CLIENT --- @usage --- -- Define a new SET_CLIENT Object. This DBObject will contain a reference to all Clients. --- DBObject = SET_CLIENT:New() -function SET_CLIENT:New() - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CLIENTS ) ) - - return self -end - ---- Add CLIENT(s) to SET_CLIENT. --- @param Core.Set#SET_CLIENT self --- @param #string AddClientNames A single name or an array of CLIENT names. --- @return self -function SET_CLIENT:AddClientsByName( AddClientNames ) - - local AddClientNamesArray = ( type( AddClientNames ) == "table" ) and AddClientNames or { AddClientNames } - - for AddClientID, AddClientName in pairs( AddClientNamesArray ) do - self:Add( AddClientName, CLIENT:FindByName( AddClientName ) ) - end - - return self -end - ---- Remove CLIENT(s) from SET_CLIENT. --- @param Core.Set#SET_CLIENT self --- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names. --- @return self -function SET_CLIENT:RemoveClientsByName( RemoveClientNames ) - - local RemoveClientNamesArray = ( type( RemoveClientNames ) == "table" ) and RemoveClientNames or { RemoveClientNames } - - for RemoveClientID, RemoveClientName in pairs( RemoveClientNamesArray ) do - self:Remove( RemoveClientName.ClientName ) - end - - return self -end - - ---- Finds a Client based on the Client Name. --- @param #SET_CLIENT self --- @param #string ClientName --- @return Wrapper.Client#CLIENT The found Client. -function SET_CLIENT:FindClient( ClientName ) - - local ClientFound = self.Set[ClientName] - return ClientFound -end - - - ---- Builds a set of clients of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_CLIENT self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_CLIENT self -function SET_CLIENT:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of clients out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_CLIENT self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_CLIENT self -function SET_CLIENT:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - - ---- Builds a set of clients of defined client types. --- Possible current types are those types known within DCS world. --- @param #SET_CLIENT self --- @param #string Types Can take those type strings known within DCS world. --- @return #SET_CLIENT self -function SET_CLIENT:FilterTypes( Types ) - if not self.Filter.Types then - self.Filter.Types = {} - end - if type( Types ) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs( Types ) do - self.Filter.Types[Type] = Type - end - return self -end - - ---- Builds a set of clients of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_CLIENT self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_CLIENT self -function SET_CLIENT:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of clients of defined client prefixes. --- All the clients starting with the given prefixes will be included within the set. --- @param #SET_CLIENT self --- @param #string Prefixes The prefix of which the client name starts with. --- @return #SET_CLIENT self -function SET_CLIENT:FilterPrefixes( Prefixes ) - if not self.Filter.ClientPrefixes then - self.Filter.ClientPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.ClientPrefixes[Prefix] = Prefix - end - return self -end - - - - ---- Starts the filtering. --- @param #SET_CLIENT self --- @return #SET_CLIENT self -function SET_CLIENT:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_CLIENT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the CLIENT --- @return #table The CLIENT -function SET_CLIENT:AddInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_CLIENT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the CLIENT --- @return #table The CLIENT -function SET_CLIENT:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Iterate the SET_CLIENT and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters. --- @param #SET_CLIENT self --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClient( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence completely in a @{Zone}, providing the CLIENT and optional parameters to the called function. --- @param #SET_CLIENT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClientInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Client#CLIENT ClientObject - function( ZoneObject, ClientObject ) - if ClientObject:IsInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence not in a @{Zone}, providing the CLIENT and optional parameters to the called function. --- @param #SET_CLIENT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClientNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Client#CLIENT ClientObject - function( ZoneObject, ClientObject ) - if ClientObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- --- @param #SET_CLIENT self --- @param Wrapper.Client#CLIENT MClient --- @return #SET_CLIENT self -function SET_CLIENT:IsIncludeObject( MClient ) - self:F2( MClient ) - - local MClientInclude = true - - if MClient then - local MClientName = MClient.UnitName - - if self.Filter.Coalitions then - local MClientCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName ) - self:T3( { "Coalition:", ClientCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == ClientCoalitionID then - MClientCoalition = true - end - end - self:T( { "Evaluated Coalition", MClientCoalition } ) - MClientInclude = MClientInclude and MClientCoalition - end - - if self.Filter.Categories then - local MClientCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName ) - self:T3( { "Category:", ClientCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == ClientCategoryID then - MClientCategory = true - end - end - self:T( { "Evaluated Category", MClientCategory } ) - MClientInclude = MClientInclude and MClientCategory - end - - if self.Filter.Types then - local MClientType = false - for TypeID, TypeName in pairs( self.Filter.Types ) do - self:T3( { "Type:", MClient:GetTypeName(), TypeName } ) - if TypeName == MClient:GetTypeName() then - MClientType = true - end - end - self:T( { "Evaluated Type", MClientType } ) - MClientInclude = MClientInclude and MClientType - end - - if self.Filter.Countries then - local MClientCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - local ClientCountryID = _DATABASE:GetCountryFromClientTemplate(MClientName) - self:T3( { "Country:", ClientCountryID, country.id[CountryName], CountryName } ) - if country.id[CountryName] and country.id[CountryName] == ClientCountryID then - MClientCountry = true - end - end - self:T( { "Evaluated Country", MClientCountry } ) - MClientInclude = MClientInclude and MClientCountry - end - - if self.Filter.ClientPrefixes then - local MClientPrefix = false - for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do - self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } ) - if string.find( MClient.UnitName, ClientPrefix, 1 ) then - MClientPrefix = true - end - end - self:T( { "Evaluated Prefix", MClientPrefix } ) - MClientInclude = MClientInclude and MClientPrefix - end - end - - self:T2( MClientInclude ) - return MClientInclude -end - ---- SET_AIRBASE - ---- SET_AIRBASE class --- @type SET_AIRBASE --- @extends Core.Set#SET_BASE -SET_AIRBASE = { - ClassName = "SET_AIRBASE", - Airbases = {}, - Filter = { - Coalitions = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - airdrome = Airbase.Category.AIRDROME, - helipad = Airbase.Category.HELIPAD, - ship = Airbase.Category.SHIP, - }, - }, -} - - ---- Creates a new SET_AIRBASE object, building a set of airbases belonging to a coalitions and categories. --- @param #SET_AIRBASE self --- @return #SET_AIRBASE self --- @usage --- -- Define a new SET_AIRBASE Object. The DatabaseSet will contain a reference to all Airbases. --- DatabaseSet = SET_AIRBASE:New() -function SET_AIRBASE:New() - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.AIRBASES ) ) - - return self -end - ---- Add AIRBASEs to SET_AIRBASE. --- @param Core.Set#SET_AIRBASE self --- @param #string AddAirbaseNames A single name or an array of AIRBASE names. --- @return self -function SET_AIRBASE:AddAirbasesByName( AddAirbaseNames ) - - local AddAirbaseNamesArray = ( type( AddAirbaseNames ) == "table" ) and AddAirbaseNames or { AddAirbaseNames } - - for AddAirbaseID, AddAirbaseName in pairs( AddAirbaseNamesArray ) do - self:Add( AddAirbaseName, AIRBASE:FindByName( AddAirbaseName ) ) - end - - return self -end - ---- Remove AIRBASEs from SET_AIRBASE. --- @param Core.Set#SET_AIRBASE self --- @param Wrapper.Airbase#AIRBASE RemoveAirbaseNames A single name or an array of AIRBASE names. --- @return self -function SET_AIRBASE:RemoveAirbasesByName( RemoveAirbaseNames ) - - local RemoveAirbaseNamesArray = ( type( RemoveAirbaseNames ) == "table" ) and RemoveAirbaseNames or { RemoveAirbaseNames } - - for RemoveAirbaseID, RemoveAirbaseName in pairs( RemoveAirbaseNamesArray ) do - self:Remove( RemoveAirbaseName.AirbaseName ) - end - - return self -end - - ---- Finds a Airbase based on the Airbase Name. --- @param #SET_AIRBASE self --- @param #string AirbaseName --- @return Wrapper.Airbase#AIRBASE The found Airbase. -function SET_AIRBASE:FindAirbase( AirbaseName ) - - local AirbaseFound = self.Set[AirbaseName] - return AirbaseFound -end - - - ---- Builds a set of airbases of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_AIRBASE self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of airbases out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_AIRBASE self --- @param #string Categories Can take the following values: "airdrome", "helipad", "ship". --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - ---- Starts the filtering. --- @param #SET_AIRBASE self --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_AIRBASE self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the AIRBASE --- @return #table The AIRBASE -function SET_AIRBASE:AddInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_AIRBASE self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the AIRBASE --- @return #table The AIRBASE -function SET_AIRBASE:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Iterate the SET_AIRBASE and call an interator function for each AIRBASE, providing the AIRBASE and optional parameters. --- @param #SET_AIRBASE self --- @param #function IteratorFunction The function that will be called when there is an alive AIRBASE in the SET_AIRBASE. The function needs to accept a AIRBASE parameter. --- @return #SET_AIRBASE self -function SET_AIRBASE:ForEachAirbase( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Core.Point#POINT_VEC2}. --- @param #SET_AIRBASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}. --- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}. -function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 ) - self:F2( PointVec2 ) - - local NearestAirbase = self:FindNearestObjectFromPointVec2( PointVec2 ) - return NearestAirbase -end - - - ---- --- @param #SET_AIRBASE self --- @param Wrapper.Airbase#AIRBASE MAirbase --- @return #SET_AIRBASE self -function SET_AIRBASE:IsIncludeObject( MAirbase ) - self:F2( MAirbase ) - - local MAirbaseInclude = true - - if MAirbase then - local MAirbaseName = MAirbase:GetName() - - if self.Filter.Coalitions then - local MAirbaseCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - local AirbaseCoalitionID = _DATABASE:GetCoalitionFromAirbase( MAirbaseName ) - self:T3( { "Coalition:", AirbaseCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == AirbaseCoalitionID then - MAirbaseCoalition = true - end - end - self:T( { "Evaluated Coalition", MAirbaseCoalition } ) - MAirbaseInclude = MAirbaseInclude and MAirbaseCoalition - end - - if self.Filter.Categories then - local MAirbaseCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - local AirbaseCategoryID = _DATABASE:GetCategoryFromAirbase( MAirbaseName ) - self:T3( { "Category:", AirbaseCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == AirbaseCategoryID then - MAirbaseCategory = true - end - end - self:T( { "Evaluated Category", MAirbaseCategory } ) - MAirbaseInclude = MAirbaseInclude and MAirbaseCategory - end - end - - self:T2( MAirbaseInclude ) - return MAirbaseInclude -end ---- This module contains the POINT classes. --- --- 1) @{Core.Point#POINT_VEC3} class, extends @{Core.Base#BASE} --- ================================================== --- The @{Core.Point#POINT_VEC3} class defines a 3D point in the simulator. --- --- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. --- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums. --- --- 1.1) POINT_VEC3 constructor --- --------------------------- --- A new POINT_VEC3 instance can be created with: --- --- * @{#POINT_VEC3.New}(): a 3D point. --- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{Dcs.DCSTypes#Vec3}. --- --- --- 2) @{Core.Point#POINT_VEC2} class, extends @{Core.Point#POINT_VEC3} --- ========================================================= --- The @{Core.Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. --- --- 2.1) POINT_VEC2 constructor --- --------------------------- --- A new POINT_VEC2 instance can be created with: --- --- * @{#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. --- * @{#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{Dcs.DCSTypes#Vec2}. --- --- === --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-12: POINT_VEC3:**Translate( Distance, Angle )** added. --- --- 2016-08-06: Made PointVec3 and Vec3, PointVec2 and Vec2 terminology used in the code consistent. --- --- * Replaced method _Point_Vec3() to **Vec3**() where the code manages a Vec3. Replaced all references to the method. --- * Replaced method _Point_Vec2() to **Vec2**() where the code manages a Vec2. Replaced all references to the method. --- * Replaced method Random_Point_Vec3() to **RandomVec3**() where the code manages a Vec3. Replaced all references to the method. --- . --- === --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Contributions: --- --- @module Point - ---- The POINT_VEC3 class --- @type POINT_VEC3 --- @extends Core.Base#BASE --- @field #number x The x coordinate in 3D space. --- @field #number y The y coordinate in 3D space. --- @field #number z The z coordiante in 3D space. --- @field Utilities.Utils#SMOKECOLOR SmokeColor --- @field Utilities.Utils#FLARECOLOR FlareColor --- @field #POINT_VEC3.RoutePointAltType RoutePointAltType --- @field #POINT_VEC3.RoutePointType RoutePointType --- @field #POINT_VEC3.RoutePointAction RoutePointAction -POINT_VEC3 = { - ClassName = "POINT_VEC3", - Metric = true, - RoutePointAltType = { - BARO = "BARO", - }, - RoutePointType = { - TurningPoint = "Turning Point", - }, - RoutePointAction = { - TurningPoint = "Turning Point", - }, -} - ---- The POINT_VEC2 class --- @type POINT_VEC2 --- @extends #POINT_VEC3 --- @field Dcs.DCSTypes#Distance x The x coordinate in meters. --- @field Dcs.DCSTypes#Distance y the y coordinate in meters. -POINT_VEC2 = { - ClassName = "POINT_VEC2", -} - - -do -- POINT_VEC3 - ---- RoutePoint AltTypes --- @type POINT_VEC3.RoutePointAltType --- @field BARO "BARO" - ---- RoutePoint Types --- @type POINT_VEC3.RoutePointType --- @field TurningPoint "Turning Point" - ---- RoutePoint Actions --- @type POINT_VEC3.RoutePointAction --- @field TurningPoint "Turning Point" - --- Constructor. - ---- Create a new POINT_VEC3 object. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. --- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing Upwards. --- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. --- @return Core.Point#POINT_VEC3 self -function POINT_VEC3:New( x, y, z ) - - local self = BASE:Inherit( self, BASE:New() ) - self.x = x - self.y = y - self.z = z - - return self -end - ---- Create a new POINT_VEC3 object from Vec3 coordinates. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. --- @return Core.Point#POINT_VEC3 self -function POINT_VEC3:NewFromVec3( Vec3 ) - - self = self:New( Vec3.x, Vec3.y, Vec3.z ) - self:F2( self ) - return self -end - - ---- Return the coordinates of the POINT_VEC3 in Vec3 format. --- @param #POINT_VEC3 self --- @return Dcs.DCSTypes#Vec3 The Vec3 coodinate. -function POINT_VEC3:GetVec3() - return { x = self.x, y = self.y, z = self.z } -end - ---- Return the coordinates of the POINT_VEC3 in Vec2 format. --- @param #POINT_VEC3 self --- @return Dcs.DCSTypes#Vec2 The Vec2 coodinate. -function POINT_VEC3:GetVec2() - return { x = self.x, y = self.z } -end - - ---- Return the x coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The x coodinate. -function POINT_VEC3:GetX() - return self.x -end - ---- Return the y coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The y coodinate. -function POINT_VEC3:GetY() - return self.y -end - ---- Return the z coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The z coodinate. -function POINT_VEC3:GetZ() - return self.z -end - ---- Set the x coordinate of the POINT_VEC3. --- @param #number x The x coordinate. -function POINT_VEC3:SetX( x ) - self.x = x -end - ---- Set the y coordinate of the POINT_VEC3. --- @param #number y The y coordinate. -function POINT_VEC3:SetY( y ) - self.y = y -end - ---- Set the z coordinate of the POINT_VEC3. --- @param #number z The z coordinate. -function POINT_VEC3:SetZ( z ) - self.z = z -end - ---- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return Dcs.DCSTypes#Vec2 Vec2 -function POINT_VEC3:GetRandomVec2InRadius( OuterRadius, InnerRadius ) - self:F2( { OuterRadius, InnerRadius } ) - - local Theta = 2 * math.pi * math.random() - local Radials = math.random() + math.random() - if Radials > 1 then - Radials = 2 - Radials - end - - local RadialMultiplier - if InnerRadius and InnerRadius <= OuterRadius then - RadialMultiplier = ( OuterRadius - InnerRadius ) * Radials + InnerRadius - else - RadialMultiplier = OuterRadius * Radials - end - - local RandomVec2 - if OuterRadius > 0 then - RandomVec2 = { x = math.cos( Theta ) * RadialMultiplier + self:GetX(), y = math.sin( Theta ) * RadialMultiplier + self:GetZ() } - else - RandomVec2 = { x = self:GetX(), y = self:GetZ() } - end - - return RandomVec2 -end - ---- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return #POINT_VEC2 -function POINT_VEC3:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) - self:F2( { OuterRadius, InnerRadius } ) - - return POINT_VEC2:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) -end - ---- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return Dcs.DCSTypes#Vec3 Vec3 -function POINT_VEC3:GetRandomVec3InRadius( OuterRadius, InnerRadius ) - - local RandomVec2 = self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) - local y = self:GetY() + math.random( InnerRadius, OuterRadius ) - local RandomVec3 = { x = RandomVec2.x, y = y, z = RandomVec2.z } - - return RandomVec3 -end - ---- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return #POINT_VEC3 -function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) - - return POINT_VEC3:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) -end - - ---- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. -function POINT_VEC3:GetDirectionVec3( TargetPointVec3 ) - return { x = TargetPointVec3:GetX() - self:GetX(), y = TargetPointVec3:GetY() - self:GetY(), z = TargetPointVec3:GetZ() - self:GetZ() } -end - ---- Get a correction in radians of the real magnetic north of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number CorrectionRadians The correction in radians. -function POINT_VEC3:GetNorthCorrectionRadians() - local TargetVec3 = self:GetVec3() - local lat, lon = coord.LOtoLL(TargetVec3) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2( north_posit.z - TargetVec3.z, north_posit.x - TargetVec3.x ) -end - - ---- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. --- @return #number DirectionRadians The direction in radians. -function POINT_VEC3:GetDirectionRadians( DirectionVec3 ) - local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x ) - --DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians() - if DirectionRadians < 0 then - DirectionRadians = DirectionRadians + 2 * math.pi -- put dir in range of 0 to 2*pi ( the full circle ) - end - return DirectionRadians -end - ---- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Distance Distance The distance in meters. -function POINT_VEC3:Get2DDistance( TargetPointVec3 ) - local TargetVec3 = TargetPointVec3:GetVec3() - local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 -end - ---- Return the 3D distance in meters between the target POINT_VEC3 and the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Distance Distance The distance in meters. -function POINT_VEC3:Get3DDistance( TargetPointVec3 ) - local TargetVec3 = TargetPointVec3:GetVec3() - local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 -end - ---- Provides a Bearing / Range string --- @param #POINT_VEC3 self --- @param #number AngleRadians The angle in randians --- @param #number Distance The distance --- @return #string The BR Text -function POINT_VEC3:ToStringBR( AngleRadians, Distance ) - - AngleRadians = UTILS.Round( UTILS.ToDegree( AngleRadians ), 0 ) - if self:IsMetric() then - Distance = UTILS.Round( Distance / 1000, 2 ) - else - Distance = UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) - end - - local s = string.format( '%03d', AngleRadians ) .. ' for ' .. Distance - - s = s .. self:GetAltitudeText() -- When the POINT is a VEC2, there will be no altitude shown. - - return s -end - ---- Provides a Bearing / Range string --- @param #POINT_VEC3 self --- @param #number AngleRadians The angle in randians --- @param #number Distance The distance --- @return #string The BR Text -function POINT_VEC3:ToStringLL( acc, DMS ) - - acc = acc or 3 - local lat, lon = coord.LOtoLL( self:GetVec3() ) - return UTILS.tostringLL(lat, lon, acc, DMS) -end - ---- Return the altitude text of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #string Altitude text. -function POINT_VEC3:GetAltitudeText() - if self:IsMetric() then - return ' at ' .. UTILS.Round( self:GetY(), 0 ) - else - return ' at ' .. UTILS.Round( UTILS.MetersToFeet( self:GetY() ), 0 ) - end -end - ---- Return a BR string from a POINT_VEC3 to the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return #string The BR text. -function POINT_VEC3:GetBRText( TargetPointVec3 ) - local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 ) - local AngleRadians = self:GetDirectionRadians( DirectionVec3 ) - local Distance = self:Get2DDistance( TargetPointVec3 ) - return self:ToStringBR( AngleRadians, Distance ) -end - ---- Sets the POINT_VEC3 metric or NM. --- @param #POINT_VEC3 self --- @param #boolean Metric true means metric, false means NM. -function POINT_VEC3:SetMetric( Metric ) - self.Metric = Metric -end - ---- Gets if the POINT_VEC3 is metric or NM. --- @param #POINT_VEC3 self --- @return #boolean Metric true means metric, false means NM. -function POINT_VEC3:IsMetric() - return self.Metric -end - ---- Add a Distance in meters from the POINT_VEC3 horizontal plane, with the given angle, and calculate the new POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. --- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. --- @return #POINT_VEC3 The new calculated POINT_VEC3. -function POINT_VEC3:Translate( Distance, Angle ) - local SX = self:GetX() - local SZ = self:GetZ() - local Radians = Angle / 180 * math.pi - local TX = Distance * math.cos( Radians ) + SX - local TZ = Distance * math.sin( Radians ) + SZ - - return POINT_VEC3:New( TX, self:GetY(), TZ ) -end - - - ---- Build an air type route point. --- @param #POINT_VEC3 self --- @param #POINT_VEC3.RoutePointAltType AltType The altitude type. --- @param #POINT_VEC3.RoutePointType Type The route point type. --- @param #POINT_VEC3.RoutePointAction Action The route point action. --- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. --- @param #boolean SpeedLocked true means the speed is locked. --- @return #table The route point. -function POINT_VEC3:RoutePointAir( AltType, Type, Action, Speed, SpeedLocked ) - self:F2( { AltType, Type, Action, Speed, SpeedLocked } ) - - local RoutePoint = {} - RoutePoint.x = self:GetX() - RoutePoint.y = self:GetZ() - RoutePoint.alt = self:GetY() - RoutePoint.alt_type = AltType - - RoutePoint.type = Type - RoutePoint.action = Action - - RoutePoint.speed = Speed / 3.6 - RoutePoint.speed_locked = true - --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] - - - RoutePoint.task = {} - RoutePoint.task.id = "ComboTask" - RoutePoint.task.params = {} - RoutePoint.task.params.tasks = {} - - - return RoutePoint -end - ---- Build an ground type route point. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Speed Speed Speed in km/h. --- @param #POINT_VEC3.RoutePointAction Formation The route point Formation. --- @return #table The route point. -function POINT_VEC3:RoutePointGround( Speed, Formation ) - self:F2( { Formation, Speed } ) - - local RoutePoint = {} - RoutePoint.x = self:GetX() - RoutePoint.y = self:GetZ() - - RoutePoint.action = Formation or "" - - - RoutePoint.speed = Speed / 3.6 - RoutePoint.speed_locked = true - --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] - - - RoutePoint.task = {} - RoutePoint.task.id = "ComboTask" - RoutePoint.task.params = {} - RoutePoint.task.params.tasks = {} - - - return RoutePoint -end - - ---- Smokes the point in a color. --- @param #POINT_VEC3 self --- @param Utilities.Utils#SMOKECOLOR SmokeColor -function POINT_VEC3:Smoke( SmokeColor ) - self:F2( { SmokeColor } ) - trigger.action.smoke( self:GetVec3(), SmokeColor ) -end - ---- Smoke the POINT_VEC3 Green. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeGreen() - self:F2() - self:Smoke( SMOKECOLOR.Green ) -end - ---- Smoke the POINT_VEC3 Red. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeRed() - self:F2() - self:Smoke( SMOKECOLOR.Red ) -end - ---- Smoke the POINT_VEC3 White. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeWhite() - self:F2() - self:Smoke( SMOKECOLOR.White ) -end - ---- Smoke the POINT_VEC3 Orange. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeOrange() - self:F2() - self:Smoke( SMOKECOLOR.Orange ) -end - ---- Smoke the POINT_VEC3 Blue. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeBlue() - self:F2() - self:Smoke( SMOKECOLOR.Blue ) -end - ---- Flares the point in a color. --- @param #POINT_VEC3 self --- @param Utilities.Utils#FLARECOLOR FlareColor --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:Flare( FlareColor, Azimuth ) - self:F2( { FlareColor } ) - trigger.action.signalFlare( self:GetVec3(), FlareColor, Azimuth and Azimuth or 0 ) -end - ---- Flare the POINT_VEC3 White. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareWhite( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.White, Azimuth ) -end - ---- Flare the POINT_VEC3 Yellow. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareYellow( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Yellow, Azimuth ) -end - ---- Flare the POINT_VEC3 Green. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareGreen( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Green, Azimuth ) -end - ---- Flare the POINT_VEC3 Red. --- @param #POINT_VEC3 self -function POINT_VEC3:FlareRed( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Red, Azimuth ) -end - -end - -do -- POINT_VEC2 - - - ---- POINT_VEC2 constructor. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. --- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. --- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. --- @return Core.Point#POINT_VEC2 -function POINT_VEC2:New( x, y, LandHeightAdd ) - - local LandHeight = land.getHeight( { ["x"] = x, ["y"] = y } ) - - LandHeightAdd = LandHeightAdd or 0 - LandHeight = LandHeight + LandHeightAdd - - self = BASE:Inherit( self, POINT_VEC3:New( x, LandHeight, y ) ) - self:F2( self ) - - return self -end - ---- Create a new POINT_VEC2 object from Vec2 coordinates. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. --- @return Core.Point#POINT_VEC2 self -function POINT_VEC2:NewFromVec2( Vec2, LandHeightAdd ) - - local LandHeight = land.getHeight( Vec2 ) - - LandHeightAdd = LandHeightAdd or 0 - LandHeight = LandHeight + LandHeightAdd - - self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) - self:F2( self ) - - return self -end - ---- Create a new POINT_VEC2 object from Vec3 coordinates. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. --- @return Core.Point#POINT_VEC2 self -function POINT_VEC2:NewFromVec3( Vec3 ) - - local self = BASE:Inherit( self, BASE:New() ) - local Vec2 = { x = Vec3.x, y = Vec3.z } - - local LandHeight = land.getHeight( Vec2 ) - - self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) - self:F2( self ) - - return self -end - ---- Return the x coordinate of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The x coodinate. -function POINT_VEC2:GetX() - return self.x -end - ---- Return the y coordinate of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The y coodinate. -function POINT_VEC2:GetY() - return self.z -end - ---- Return the altitude of the land at the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The land altitude. -function POINT_VEC2:GetAlt() - return land.getHeight( { x = self.x, y = self.z } ) -end - ---- Set the x coordinate of the POINT_VEC2. --- @param #number x The x coordinate. -function POINT_VEC2:SetX( x ) - self.x = x -end - ---- Set the y coordinate of the POINT_VEC2. --- @param #number y The y coordinate. -function POINT_VEC2:SetY( y ) - self.z = y -end - - - ---- Calculate the distance from a reference @{#POINT_VEC2}. --- @param #POINT_VEC2 self --- @param #POINT_VEC2 PointVec2Reference The reference @{#POINT_VEC2}. --- @return Dcs.DCSTypes#Distance The distance from the reference @{#POINT_VEC2} in meters. -function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference ) - self:F2( PointVec2Reference ) - - local Distance = ( ( PointVec2Reference:GetX() - self:GetX() ) ^ 2 + ( PointVec2Reference:GetY() - self:GetY() ) ^2 ) ^0.5 - - self:T2( Distance ) - return Distance -end - ---- Calculate the distance from a reference @{Dcs.DCSTypes#Vec2}. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{Dcs.DCSTypes#Vec2}. --- @return Dcs.DCSTypes#Distance The distance from the reference @{Dcs.DCSTypes#Vec2} in meters. -function POINT_VEC2:DistanceFromVec2( Vec2Reference ) - self:F2( Vec2Reference ) - - local Distance = ( ( Vec2Reference.x - self:GetX() ) ^ 2 + ( Vec2Reference.y - self:GetY() ) ^2 ) ^0.5 - - self:T2( Distance ) - return Distance -end - - ---- Return no text for the altitude of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #string Empty string. -function POINT_VEC2:GetAltitudeText() - return '' -end - ---- Add a Distance in meters from the POINT_VEC2 orthonormal plane, with the given angle, and calculate the new POINT_VEC2. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. --- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. --- @return #POINT_VEC2 The new calculated POINT_VEC2. -function POINT_VEC2:Translate( Distance, Angle ) - local SX = self:GetX() - local SY = self:GetY() - local Radians = Angle / 180 * math.pi - local TX = Distance * math.cos( Radians ) + SX - local TY = Distance * math.sin( Radians ) + SY - - return POINT_VEC2:New( TX, TY ) -end - -end - - ---- This module contains the MESSAGE class. --- --- 1) @{Core.Message#MESSAGE} class, extends @{Core.Base#BASE} --- ================================================= --- Message System to display Messages to Clients, Coalitions or All. --- Messages are shown on the display panel for an amount of seconds, and will then disappear. --- Messages can contain a category which is indicating the category of the message. --- --- 1.1) MESSAGE construction methods --- --------------------------------- --- Messages are created with @{Core.Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet. --- To send messages, you need to use the To functions. --- --- 1.2) Send messages with MESSAGE To methods --- ------------------------------------------ --- Messages are sent to: --- --- * Clients with @{Core.Message#MESSAGE.ToClient}. --- * Coalitions with @{Core.Message#MESSAGE.ToCoalition}. --- * All Players with @{Core.Message#MESSAGE.ToAll}. --- --- @module Message --- @author FlightControl - ---- The MESSAGE class --- @type MESSAGE --- @extends Core.Base#BASE -MESSAGE = { - ClassName = "MESSAGE", - MessageCategory = 0, - MessageID = 0, -} - - ---- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. --- @param self --- @param #string MessageText is the text of the Message. --- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. --- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ". --- @return #MESSAGE --- @usage --- -- Create a series of new Messages. --- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". --- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win". --- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". --- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" ) --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" ) --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score") -function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { MessageText, MessageDuration, MessageCategory } ) - - -- When no MessageCategory is given, we don't show it as a title... - if MessageCategory and MessageCategory ~= "" then - if MessageCategory:sub(-1) ~= "\n" then - self.MessageCategory = MessageCategory .. ": " - else - self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n" - end - else - self.MessageCategory = "" - end - - self.MessageDuration = MessageDuration or 5 - self.MessageTime = timer.getTime() - self.MessageText = MessageText - - self.MessageSent = false - self.MessageGroup = false - self.MessageCoalition = false - - return self -end - ---- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player". --- @param #MESSAGE self --- @param Wrapper.Client#CLIENT Client is the Group of the Client. --- @return #MESSAGE --- @usage --- -- Send the 2 messages created with the @{New} method to the Client Group. --- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1. --- ClientGroup = Group.getByName( "ClientGroup" ) --- --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- or --- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- or --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) --- MessageClient1:ToClient( ClientGroup ) --- MessageClient2:ToClient( ClientGroup ) -function MESSAGE:ToClient( Client ) - self:F( Client ) - - if Client and Client:GetClientGroupID() then - - local ClientGroupID = Client:GetClientGroupID() - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end - ---- Sends a MESSAGE to a Group. --- @param #MESSAGE self --- @param Wrapper.Group#GROUP Group is the Group. --- @return #MESSAGE -function MESSAGE:ToGroup( Group ) - self:F( Group.GroupName ) - - if Group then - - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end ---- Sends a MESSAGE to the Blue coalition. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the BLUE coalition. --- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() --- or --- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() --- or --- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageBLUE:ToBlue() -function MESSAGE:ToBlue() - self:F() - - self:ToCoalition( coalition.side.BLUE ) - - return self -end - ---- Sends a MESSAGE to the Red Coalition. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the RED coalition. --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() --- or --- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() --- or --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageRED:ToRed() -function MESSAGE:ToRed( ) - self:F() - - self:ToCoalition( coalition.side.RED ) - - return self -end - ---- Sends a MESSAGE to a Coalition. --- @param #MESSAGE self --- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the RED coalition. --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) --- or --- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) --- or --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageRED:ToCoalition( coalition.side.RED ) -function MESSAGE:ToCoalition( CoalitionSide ) - self:F( CoalitionSide ) - - if CoalitionSide then - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end - ---- Sends a MESSAGE to all players. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created to all players. --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() --- or --- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() --- or --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) --- MessageAll:ToAll() -function MESSAGE:ToAll() - self:F() - - self:ToCoalition( coalition.side.RED ) - self:ToCoalition( coalition.side.BLUE ) - - return self -end - - - ------ The MESSAGEQUEUE class ----- @type MESSAGEQUEUE ---MESSAGEQUEUE = { --- ClientGroups = {}, --- CoalitionSides = {} ---} --- ---function MESSAGEQUEUE:New( RefreshInterval ) --- local self = BASE:Inherit( self, BASE:New() ) --- self:F( { RefreshInterval } ) --- --- self.RefreshInterval = RefreshInterval --- --- --self.DisplayFunction = routines.scheduleFunction( self._DisplayMessages, { self }, 0, RefreshInterval ) --- self.DisplayFunction = SCHEDULER:New( self, self._DisplayMessages, {}, 0, RefreshInterval ) --- --- return self ---end --- ------ This function is called automatically by the MESSAGEQUEUE scheduler. ---function MESSAGEQUEUE:_DisplayMessages() --- --- -- First we display all messages that a coalition needs to receive... Also those who are not in a client (CA module clients...). --- for CoalitionSideID, CoalitionSideData in pairs( self.CoalitionSides ) do --- for MessageID, MessageData in pairs( CoalitionSideData.Messages ) do --- if MessageData.MessageSent == false then --- --trigger.action.outTextForCoalition( CoalitionSideID, MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageSent = true --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- end --- --- -- Then we send the messages for each individual client, but also to be included are those Coalition messages for the Clients who belong to a coalition. --- -- Because the Client messages will overwrite the Coalition messages (for that Client). --- for ClientGroupName, ClientGroupData in pairs( self.ClientGroups ) do --- for MessageID, MessageData in pairs( ClientGroupData.Messages ) do --- if MessageData.MessageGroup == false then --- trigger.action.outTextForGroup( Group.getByName(ClientGroupName):getID(), MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageGroup = true --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- --- -- Now check if the Client also has messages that belong to the Coalition of the Client... --- for CoalitionSideID, CoalitionSideData in pairs( self.CoalitionSides ) do --- for MessageID, MessageData in pairs( CoalitionSideData.Messages ) do --- local CoalitionGroup = Group.getByName( ClientGroupName ) --- if CoalitionGroup and CoalitionGroup:getCoalition() == CoalitionSideID then --- if MessageData.MessageCoalition == false then --- trigger.action.outTextForGroup( Group.getByName(ClientGroupName):getID(), MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageCoalition = true --- end --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- end --- end --- --- return true ---end --- ------ The _MessageQueue object is created when the MESSAGE class module is loaded. -----_MessageQueue = MESSAGEQUEUE:New( 0.5 ) --- ---- This module contains the **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes. --- ## Finite State Machines (FSM) are design patterns allowing efficient (long-lasting) processes and workflows. --- --- ![Banner Image](..\Presentations\FSM\Dia1.JPG) --- --- A FSM can only be in one of a finite number of states. --- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. --- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. --- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. --- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. --- --- The FSM class supports a **hierarchical implementation of a Finite State Machine**, --- that is, it allows to **embed existing FSM implementations in a master FSM**. --- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. --- --- ![Workflow Example](..\Presentations\FSM\Dia2.JPG) --- --- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, --- orders him to destroy x targets and account the results. --- Other examples of ready made FSM could be: --- --- * route a plane to a zone flown by a human --- * detect targets by an AI and report to humans --- * account for destroyed targets by human players --- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle --- * let an AI patrol a zone --- --- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, --- because **the goal of MOOSE is to simplify mission design complexity for mission building**. --- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. --- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, --- and tailored** by mission designers through **the implementation of Transition Handlers**. --- Each of these FSM implementation classes start either with: --- --- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. --- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. --- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. --- --- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. --- --- ##__Dislaimer:__ --- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. --- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) --- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. --- Additionally, I've added extendability and created an API that allows seamless FSM implementation. --- --- === --- --- # 1) @{Core.Fsm#FSM} class, extends @{Core.Base#BASE} --- --- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG) --- --- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. --- The derived FSM\_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component. --- --- Finite State Machines have **Transition Rules**, **Transition Handlers** and **Event Triggers**. --- --- The **Transition Rules** define the "Process Flow Boundaries", that is, --- the path that can be followed hopping from state to state upon triggered events. --- If an event is triggered, and there is no valid path found for that event, --- an error will be raised and the FSM will stop functioning. --- --- The **Transition Handlers** are special methods that can be defined by the mission designer, following a defined syntax. --- If the FSM object finds a method of such a handler, then the method will be called by the FSM, passing specific parameters. --- The method can then define its own custom logic to implement the FSM workflow, and to conduct other actions. --- --- The **Event Triggers** are methods that are defined by the FSM, which the mission designer can use to implement the workflow. --- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. --- --- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. --- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. --- --- ## 1.1) FSM Linear Transitions --- --- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. --- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. --- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. --- --- ### 1.1.1) FSM Transition Rules --- --- The FSM has transition rules that it follows and validates, as it walks the process. --- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. --- --- The method @{#FSM.AddTransition}() specifies a new possible Transition Rule for the FSM. --- --- The initial state can be defined using the method @{#FSM.SetStartState}(). The default start state of an FSM is "None". --- --- Find below an example of a Linear Transition Rule definition for an FSM. --- --- local Fsm3Switch = FSM:New() -- #FsmDemo --- FsmSwitch:SetStartState( "Off" ) --- FsmSwitch:AddTransition( "Off", "SwitchOn", "On" ) --- FsmSwitch:AddTransition( "Off", "SwitchMiddle", "Middle" ) --- FsmSwitch:AddTransition( "On", "SwitchOff", "Off" ) --- FsmSwitch:AddTransition( "Middle", "SwitchOff", "Off" ) --- --- The above code snippet models a 3-way switch Linear Transition: --- --- * It can be switched **On** by triggering event **SwitchOn**. --- * It can be switched to the **Middle** position, by triggering event **SwitchMiddle**. --- * It can be switched **Off** by triggering event **SwitchOff**. --- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. --- --- ### Some additional comments: --- --- Note that Linear Transition Rules **can be declared in a few variations**: --- --- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. --- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. --- --- The below code snippet shows how the two last lines can be rewritten and consensed. --- --- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) --- --- ### 1.1.2) Transition Handling --- --- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG) --- --- An FSM transitions in **4 moments** when an Event is being triggered and processed. --- The mission designer can define for each moment specific logic within methods implementations following a defined API syntax. --- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be triggered. --- --- * To handle **State** transition moments, create methods starting with OnLeave or OnEnter concatenated with the State name. --- * To handle **Event** transition moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. --- --- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition!** --- --- Transition Handler methods need to follow the above specified naming convention, but are also passed parameters from the FSM. --- These parameters are on the correct order: From, Event, To: --- --- * From = A string containing the From state. --- * Event = A string containing the Event name that was triggered. --- * To = A string containing the To state. --- --- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). --- --- ### 1.1.3) Event Triggers --- --- ![Event Triggers](..\Presentations\FSM\Dia5.JPG) --- --- The FSM creates for each Event two **Event Trigger methods**. --- There are two modes how Events can be triggered, which is **synchronous** and **asynchronous**: --- --- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. --- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. --- --- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. --- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. --- --- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. --- --- function FSM:OnAfterEvent( From, Event, To, Amount ) --- self:E( { Amount = Amount } ) --- end --- --- local Amount = 1 --- FSM:__Event( 5, Amount ) --- --- Amount = Amount + 1 --- FSM:Event( Text, Amount ) --- --- In this example, the **:OnAfterEvent**() Transition Handler implementation will get called when **Event** is being triggered. --- Before we go into more detail, let's look at the last 4 lines of the example. --- The last line triggers synchronously the **Event**, and passes Amount as a parameter. --- The 3rd last line of the example triggers asynchronously **Event**. --- Event will be processed after 5 seconds, and Amount is given as a parameter. --- --- The output of this little code fragment will be: --- --- * Amount = 2 --- * Amount = 2 --- --- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! --- --- ### 1.1.4) Linear Transition Example --- --- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) --- --- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare. --- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build. --- Have a look at the source code. The source code is also further explained below in this section. --- --- The example creates a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to state **Green**. --- Two Linear Transition Rules are created, where upon the event **Switch**, --- the FsmDemo will transition from state **Green** to **Red** and from **Red** back to **Green**. --- --- ![Transition Example](..\Presentations\FSM\Dia6.JPG) --- --- local FsmDemo = FSM:New() -- #FsmDemo --- FsmDemo:SetStartState( "Green" ) --- FsmDemo:AddTransition( "Green", "Switch", "Red" ) --- FsmDemo:AddTransition( "Red", "Switch", "Green" ) --- --- In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. --- The next code implements this through the event handling method **OnAfterSwitch**. --- --- ![Transition Flow](..\Presentations\FSM\Dia7.JPG) --- --- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) --- self:E( { From, Event, To, FsmUnit } ) --- --- if From == "Green" then --- FsmUnit:Flare(FLARECOLOR.Green) --- else --- if From == "Red" then --- FsmUnit:Flare(FLARECOLOR.Red) --- end --- end --- self:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. --- end --- --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds. --- --- The OnAfterSwitch implements a loop. The last line of the code fragment triggers the Switch Event within 5 seconds. --- Upon the event execution (after 5 seconds), the OnAfterSwitch method is called of FsmDemo (cfr. the double point notation!!! ":"). --- The OnAfterSwitch method receives from the FSM the 3 transition parameter details ( From, Event, To ), --- and one additional parameter that was given when the event was triggered, which is in this case the Unit that is used within OnSwitchAfter. --- --- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) --- --- For debugging reasons the received parameters are traced within the DCS.log. --- --- self:E( { From, Event, To, FsmUnit } ) --- --- The method will check if the From state received is either "Green" or "Red" and will flare the respective color from the FsmUnit. --- --- if From == "Green" then --- FsmUnit:Flare(FLARECOLOR.Green) --- else --- if From == "Red" then --- FsmUnit:Flare(FLARECOLOR.Red) --- end --- end --- --- It is important that the Switch event is again triggered, otherwise, the FsmDemo would stop working after having the first Event being handled. --- --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. --- --- The below code fragment extends the FsmDemo, demonstrating multiple **From states declared as a table**, adding a **Linear Transition Rule**. --- The new event **Stop** will cancel the Switching process. --- The transition for event Stop can be executed if the current state of the FSM is either "Red" or "Green". --- --- local FsmDemo = FSM:New() -- #FsmDemo --- FsmDemo:SetStartState( "Green" ) --- FsmDemo:AddTransition( "Green", "Switch", "Red" ) --- FsmDemo:AddTransition( "Red", "Switch", "Green" ) --- FsmDemo:AddTransition( { "Red", "Green" }, "Stop", "Stopped" ) --- --- The transition for event Stop can also be simplified, as any current state of the FSM is valid. --- --- FsmDemo:AddTransition( "*", "Stop", "Stopped" ) --- --- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. --- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. --- --- ## 1.5) FSM Hierarchical Transitions --- --- Hierarchical Transitions allow to re-use readily available and implemented FSMs. --- This becomes in very useful for mission building, where mission designers build complex processes and workflows, --- combining smaller FSMs to one single FSM. --- --- The FSM can embed **Sub-FSMs** that will execute and return **multiple possible Return (End) States**. --- Depending upon **which state is returned**, the main FSM can continue the flow **triggering specific events**. --- --- The method @{#FSM.AddProcess}() adds a new Sub-FSM to the FSM. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) --- YYYY-MM-DD: CLASS:**NewFunction( Params )** added --- --- Hereby the change log: --- --- * 2016-12-18: Released. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements. --- --- ### Authors: --- --- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. --- --- @module Fsm - -do -- FSM - - --- FSM class - -- @type FSM - -- @extends Core.Base#BASE - FSM = { - ClassName = "FSM", - } - - --- Creates a new FSM object. - -- @param #FSM self - -- @return #FSM - function FSM:New( FsmT ) - - -- Inherits from BASE - self = BASE:Inherit( self, BASE:New() ) - - self.options = options or {} - self.options.subs = self.options.subs or {} - self.current = self.options.initial or 'none' - self.Events = {} - self.subs = {} - self.endstates = {} - - self.Scores = {} - - self._StartState = "none" - self._Transitions = {} - self._Processes = {} - self._EndStates = {} - self._Scores = {} - - self.CallScheduler = SCHEDULER:New( self ) - - - return self - end - - - --- Sets the start state of the FSM. - -- @param #FSM self - -- @param #string State A string defining the start state. - function FSM:SetStartState( State ) - - self._StartState = State - self.current = State - end - - - --- Returns the start state of the FSM. - -- @param #FSM self - -- @return #string A string containing the start state. - function FSM:GetStartState() - - return self._StartState or {} - end - - --- Add a new transition rule to the FSM. - -- A transition rule defines when and if the FSM can transition from a state towards another state upon a triggered event. - -- @param #FSM self - -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. - -- @param #string Event The Event name. - -- @param #string To The To state. - function FSM:AddTransition( From, Event, To ) - - local Transition = {} - Transition.From = From - Transition.Event = Event - Transition.To = To - - self:E( Transition ) - - self._Transitions[Transition] = Transition - self:_eventmap( self.Events, Transition ) - end - - - --- Returns a table of the transition rules defined within the FSM. - -- @return #table - function FSM:GetTransitions() - - return self._Transitions or {} - end - - --- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task. - -- @param #FSM self - -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. - -- @param #string Event The Event name. - -- @param Core.Fsm#FSM_PROCESS Process An sub-process FSM. - -- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM. - -- @return Core.Fsm#FSM_PROCESS The SubFSM. - function FSM:AddProcess( From, Event, Process, ReturnEvents ) - self:E( { From, Event, Process, ReturnEvents } ) - - local Sub = {} - Sub.From = From - Sub.Event = Event - Sub.fsm = Process - Sub.StartEvent = "Start" - Sub.ReturnEvents = ReturnEvents - - self._Processes[Sub] = Sub - - self:_submap( self.subs, Sub, nil ) - - self:AddTransition( From, Event, From ) - - return Process - end - - - --- Returns a table of the SubFSM rules defined within the FSM. - -- @return #table - function FSM:GetProcesses() - - return self._Processes or {} - end - - function FSM:GetProcess( From, Event ) - - for ProcessID, Process in pairs( self:GetProcesses() ) do - if Process.From == From and Process.Event == Event then - self:E( Process ) - return Process.fsm - end - end - - error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" ) - end - - --- Adds an End state. - function FSM:AddEndState( State ) - - self._EndStates[State] = State - self.endstates[State] = State - end - - --- Returns the End states. - function FSM:GetEndStates() - - return self._EndStates or {} - end - - - --- Adds a score for the FSM to be achieved. - -- @param #FSM self - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM self - function FSM:AddScore( State, ScoreText, Score ) - self:F2( { State, ScoreText, Score } ) - - self._Scores[State] = self._Scores[State] or {} - self._Scores[State].ScoreText = ScoreText - self._Scores[State].Score = Score - - return self - end - - --- Adds a score for the FSM_PROCESS to be achieved. - -- @param #FSM self - -- @param #string From is the From State of the main process. - -- @param #string Event is the Event of the main process. - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM self - function FSM:AddScoreProcess( From, Event, State, ScoreText, Score ) - self:F2( { Event, State, ScoreText, Score } ) - - local Process = self:GetProcess( From, Event ) - - self:E( { Process = Process._Name, Scores = Process._Scores, State = State, ScoreText = ScoreText, Score = Score } ) - Process._Scores[State] = Process._Scores[State] or {} - Process._Scores[State].ScoreText = ScoreText - Process._Scores[State].Score = Score - - return Process - end - - --- Returns a table with the scores defined. - function FSM:GetScores() - - return self._Scores or {} - end - - --- Returns a table with the Subs defined. - function FSM:GetSubs() - - return self.options.subs - end - - - function FSM:LoadCallBacks( CallBackTable ) - - for name, callback in pairs( CallBackTable or {} ) do - self[name] = callback - end - - end - - function FSM:_eventmap( Events, EventStructure ) - - local Event = EventStructure.Event - local __Event = "__" .. EventStructure.Event - self[Event] = self[Event] or self:_create_transition(Event) - self[__Event] = self[__Event] or self:_delayed_transition(Event) - self:T( "Added methods: " .. Event .. ", " .. __Event ) - Events[Event] = self.Events[Event] or { map = {} } - self:_add_to_map( Events[Event].map, EventStructure ) - - end - - function FSM:_submap( subs, sub, name ) - self:F( { sub = sub, name = name } ) - subs[sub.From] = subs[sub.From] or {} - subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {} - - -- Make the reference table weak. - -- setmetatable( subs[sub.From][sub.Event], { __mode = "k" } ) - - subs[sub.From][sub.Event][sub] = {} - subs[sub.From][sub.Event][sub].fsm = sub.fsm - subs[sub.From][sub.Event][sub].StartEvent = sub.StartEvent - subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop. - subs[sub.From][sub.Event][sub].name = name - subs[sub.From][sub.Event][sub].fsmparent = self - end - - - function FSM:_call_handler(handler, params) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, unpack(params) ) - end - end - - function FSM._handler( self, EventName, ... ) - - self:E( { EventName, ... } ) - - local Can, to = self:can( EventName ) - self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) - - if Can then - local from = self.current - local params = { from, EventName, to, ... } - - if self:_call_handler("onbefore" .. EventName, params) == false - or self:_call_handler("OnBefore" .. EventName, params) == false - or self:_call_handler("onleave" .. from, params) == false - or self:_call_handler("OnLeave" .. from, params) == false then - return false - end - - self.current = to - - local execute = true - - local subtable = self:_gosub( from, EventName ) - for _, sub in pairs( subtable ) do - --if sub.nextevent then - -- self:F2( "nextevent = " .. sub.nextevent ) - -- self[sub.nextevent]( self ) - --end - self:E( "calling sub start event: " .. sub.StartEvent ) - sub.fsm.fsmparent = self - sub.fsm.ReturnEvents = sub.ReturnEvents - sub.fsm[sub.StartEvent]( sub.fsm ) - execute = false - end - - local fsmparent, Event = self:_isendstate( to ) - if fsmparent and Event then - self:F2( { "end state: ", fsmparent, Event } ) - self:_call_handler("onenter" .. to, params) - self:_call_handler("OnEnter" .. to, params) - self:_call_handler("onafter" .. EventName, params) - self:_call_handler("OnAfter" .. EventName, params) - self:_call_handler("onstatechange", params) - fsmparent[Event]( fsmparent ) - execute = false - end - - if execute then - -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! - --if from ~= to then - self:_call_handler("onenter" .. to, params) - self:_call_handler("OnEnter" .. to, params) - --end - - self:_call_handler("onafter" .. EventName, params) - self:_call_handler("OnAfter" .. EventName, params) - - self:_call_handler("onstatechange", params) - end - end - - return nil - end - - function FSM:_delayed_transition( EventName ) - self:E( { EventName = EventName } ) - return function( self, DelaySeconds, ... ) - self:T( "Delayed Event: " .. EventName ) - local CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) - self:T( { CallID = CallID } ) - end - end - - function FSM:_create_transition( EventName ) - self:E( { Event = EventName } ) - return function( self, ... ) return self._handler( self, EventName , ... ) end - end - - function FSM:_gosub( ParentFrom, ParentEvent ) - local fsmtable = {} - if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then - self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } ) - return self.subs[ParentFrom][ParentEvent] - else - return {} - end - end - - function FSM:_isendstate( Current ) - local FSMParent = self.fsmparent - if FSMParent and self.endstates[Current] then - self:E( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) - FSMParent.current = Current - local ParentFrom = FSMParent.current - self:E( ParentFrom ) - self:E( self.ReturnEvents ) - local Event = self.ReturnEvents[Current] - self:E( { ParentFrom, Event, self.ReturnEvents } ) - if Event then - return FSMParent, Event - else - self:E( { "Could not find parent event name for state ", ParentFrom } ) - end - end - - return nil - end - - function FSM:_add_to_map( Map, Event ) - self:F3( { Map, Event } ) - if type(Event.From) == 'string' then - Map[Event.From] = Event.To - else - for _, From in ipairs(Event.From) do - Map[From] = Event.To - end - end - self:T3( { Map, Event } ) - end - - function FSM:GetState() - return self.current - end - - - function FSM:Is( State ) - return self.current == State - end - - function FSM:is(state) - return self.current == state - end - - function FSM:can(e) - self:E( { e, self.Events, self.Events[e] } ) - local Event = self.Events[e] - self:F3( { self.current, Event } ) - local To = Event and Event.map[self.current] or Event.map['*'] - return To ~= nil, To - end - - function FSM:cannot(e) - return not self:can(e) - end - -end - -do -- FSM_CONTROLLABLE - - --- FSM_CONTROLLABLE class - -- @type FSM_CONTROLLABLE - -- @field Wrapper.Controllable#CONTROLLABLE Controllable - -- @extends Core.Fsm#FSM - FSM_CONTROLLABLE = { - ClassName = "FSM_CONTROLLABLE", - } - - --- Creates a new FSM_CONTROLLABLE object. - -- @param #FSM_CONTROLLABLE self - -- @param #table FSMT Finite State Machine Table - -- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @return #FSM_CONTROLLABLE - function FSM_CONTROLLABLE:New( FSMT, Controllable ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE - - if Controllable then - self:SetControllable( Controllable ) - end - - return self - end - - --- Sets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @param #FSM_CONTROLLABLE self - -- @param Wrapper.Controllable#CONTROLLABLE FSMControllable - -- @return #FSM_CONTROLLABLE - function FSM_CONTROLLABLE:SetControllable( FSMControllable ) - self:F( FSMControllable ) - self.Controllable = FSMControllable - end - - --- Gets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @param #FSM_CONTROLLABLE self - -- @return Wrapper.Controllable#CONTROLLABLE - function FSM_CONTROLLABLE:GetControllable() - return self.Controllable - end - - function FSM_CONTROLLABLE:_call_handler( handler, params ) - - local ErrorHandler = function( errmsg ) - - env.info( "Error in SCHEDULER function:" .. errmsg ) - if debug ~= nil then - env.info( debug.traceback() ) - end - - return errmsg - end - - if self[handler] then - self:E( "Calling " .. handler ) - return xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) - --return self[handler]( self, self.Controllable, unpack( params ) ) - end - end - -end - -do -- FSM_PROCESS - - --- FSM_PROCESS class - -- @type FSM_PROCESS - -- @field Tasking.Task#TASK Task - -- @extends Core.Fsm#FSM_CONTROLLABLE - FSM_PROCESS = { - ClassName = "FSM_PROCESS", - } - - --- Creates a new FSM_PROCESS object. - -- @param #FSM_PROCESS self - -- @return #FSM_PROCESS - function FSM_PROCESS:New( Controllable, Task ) - - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS - - self:F( Controllable, Task ) - - self:Assign( Controllable, Task ) - - return self - end - - function FSM_PROCESS:Init( FsmProcess ) - self:E( "No Initialisation" ) - end - - --- Creates a new FSM_PROCESS object based on this FSM_PROCESS. - -- @param #FSM_PROCESS self - -- @return #FSM_PROCESS - function FSM_PROCESS:Copy( Controllable, Task ) - self:E( { self:GetClassNameAndID() } ) - - local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS - - NewFsm:Assign( Controllable, Task ) - - -- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS - NewFsm:Init( self ) - - -- Set Start State - NewFsm:SetStartState( self:GetStartState() ) - - -- Copy Transitions - for TransitionID, Transition in pairs( self:GetTransitions() ) do - NewFsm:AddTransition( Transition.From, Transition.Event, Transition.To ) - end - - -- Copy Processes - for ProcessID, Process in pairs( self:GetProcesses() ) do - self:E( { Process} ) - local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents ) - end - - -- Copy End States - for EndStateID, EndState in pairs( self:GetEndStates() ) do - self:E( EndState ) - NewFsm:AddEndState( EndState ) - end - - -- Copy the score tables - for ScoreID, Score in pairs( self:GetScores() ) do - self:E( Score ) - NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score ) - end - - return NewFsm - end - - --- Sets the task of the process. - -- @param #FSM_PROCESS self - -- @param Tasking.Task#TASK Task - -- @return #FSM_PROCESS - function FSM_PROCESS:SetTask( Task ) - - self.Task = Task - - return self - end - - --- Gets the task of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.Task#TASK - function FSM_PROCESS:GetTask() - - return self.Task - end - - --- Gets the mission of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.Mission#MISSION - function FSM_PROCESS:GetMission() - - return self.Task.Mission - end - - --- Gets the mission of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.CommandCenter#COMMANDCENTER - function FSM_PROCESS:GetCommandCenter() - - return self:GetTask():GetMission():GetCommandCenter() - end - --- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP. - - --- Send a message of the @{Task} to the Group of the Unit. --- @param #FSM_PROCESS self -function FSM_PROCESS:Message( Message ) - self:F( { Message = Message } ) - - local CC = self:GetCommandCenter() - local TaskGroup = self.Controllable:GetGroup() - - local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit - PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets. - local Callsign = self.Controllable:GetCallsign() - local Prefix = Callsign and " @ " .. Callsign .. PlayerName or "" - - Message = Prefix .. ": " .. Message - CC:MessageToGroup( Message, TaskGroup ) -end - - - - - --- Assign the process to a @{Unit} and activate the process. - -- @param #FSM_PROCESS self - -- @param Task.Tasking#TASK Task - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @return #FSM_PROCESS self - function FSM_PROCESS:Assign( ProcessUnit, Task ) - self:E( { Task, ProcessUnit } ) - - self:SetControllable( ProcessUnit ) - self:SetTask( Task ) - - --self.ProcessGroup = ProcessUnit:GetGroup() - - return self - end - - --- Adds a score for the FSM_PROCESS to be achieved. - -- @param #FSM_PROCESS self - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM_PROCESS self - function FSM_PROCESS:AddScore( State, ScoreText, Score ) - self:F2( { State, ScoreText, Score } ) - - self.Scores[State] = self.Scores[State] or {} - self.Scores[State].ScoreText = ScoreText - self.Scores[State].Score = Score - - return self - end - - function FSM_PROCESS:onenterAssigned( ProcessUnit ) - self:E( "Assign" ) - - self.Task:Assign() - end - - function FSM_PROCESS:onenterFailed( ProcessUnit ) - self:E( "Failed" ) - - self.Task:Fail() - end - - function FSM_PROCESS:onenterSuccess( ProcessUnit ) - self:E( "Success" ) - - self.Task:Success() - end - - --- StateMachine callback function for a FSM_PROCESS - -- @param #FSM_PROCESS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function FSM_PROCESS:onstatechange( ProcessUnit, From, Event, To, Dummy ) - self:E( { ProcessUnit, From, Event, To, Dummy, self:IsTrace() } ) - - if self:IsTrace() then - MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() - end - - self:E( self.Scores[To] ) - -- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects... - if self.Scores[To] then - - local Task = self.Task - local Scoring = Task:GetScoring() - if Scoring then - Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score ) - end - end - end - -end - -do -- FSM_TASK - - --- FSM_TASK class - -- @type FSM_TASK - -- @field Tasking.Task#TASK Task - -- @extends Core.Fsm#FSM - FSM_TASK = { - ClassName = "FSM_TASK", - } - - --- Creates a new FSM_TASK object. - -- @param #FSM_TASK self - -- @param #table FSMT - -- @param Tasking.Task#TASK Task - -- @param Wrapper.Unit#UNIT TaskUnit - -- @return #FSM_TASK - function FSM_TASK:New( FSMT ) - - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK - - self["onstatechange"] = self.OnStateChange - - return self - end - - function FSM_TASK:_call_handler( handler, params ) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, unpack( params ) ) - end - end - -end -- FSM_TASK - -do -- FSM_SET - - --- FSM_SET class - -- @type FSM_SET - -- @field Core.Set#SET_BASE Set - -- @extends Core.Fsm#FSM - FSM_SET = { - ClassName = "FSM_SET", - } - - --- Creates a new FSM_SET object. - -- @param #FSM_SET self - -- @param #table FSMT Finite State Machine Table - -- @param Set_SET_BASE FSMSet (optional) The Set object that the FSM_SET governs. - -- @return #FSM_SET - function FSM_SET:New( FSMSet ) - - -- Inherits from BASE - self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET - - if FSMSet then - self:Set( FSMSet ) - end - - return self - end - - --- Sets the SET_BASE object that the FSM_SET governs. - -- @param #FSM_SET self - -- @param Core.Set#SET_BASE FSMSet - -- @return #FSM_SET - function FSM_SET:Set( FSMSet ) - self:F( FSMSet ) - self.Set = FSMSet - end - - --- Gets the SET_BASE object that the FSM_SET governs. - -- @param #FSM_SET self - -- @return Core.Set#SET_BASE - function FSM_SET:Get() - return self.Controllable - end - - function FSM_SET:_call_handler( handler, params ) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, self.Set, unpack( params ) ) - end - end - -end -- FSM_SET - ---- This module contains the OBJECT class. --- --- 1) @{Wrapper.Object#OBJECT} class, extends @{Core.Base#BASE} --- =========================================================== --- The @{Wrapper.Object#OBJECT} class is a wrapper class to handle the DCS Object objects: --- --- * Support all DCS Object APIs. --- * Enhance with Object specific APIs not in the DCS Object API set. --- * Manage the "state" of the DCS Object. --- --- 1.1) OBJECT constructor: --- ------------------------------ --- The OBJECT class provides the following functions to construct a OBJECT instance: --- --- * @{Wrapper.Object#OBJECT.New}(): Create a OBJECT instance. --- --- 1.2) OBJECT methods: --- -------------------------- --- The following methods can be used to identify an Object object: --- --- * @{Wrapper.Object#OBJECT.GetID}(): Returns the ID of the Object object. --- --- === --- --- @module Object - ---- The OBJECT class --- @type OBJECT --- @extends Core.Base#BASE --- @field #string ObjectName The name of the Object. -OBJECT = { - ClassName = "OBJECT", - ObjectName = "", -} - ---- A DCSObject --- @type DCSObject --- @field id_ The ID of the controllable in DCS - ---- Create a new OBJECT from a DCSObject --- @param #OBJECT self --- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name --- @return #OBJECT self -function OBJECT:New( ObjectName, Test ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( ObjectName ) - self.ObjectName = ObjectName - - return self -end - - ---- Returns the unit's unique identifier. --- @param Wrapper.Object#OBJECT self --- @return Dcs.DCSWrapper.Object#Object.ID ObjectID --- @return #nil The DCS Object is not existing or alive. -function OBJECT:GetID() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - - if DCSObject then - local ObjectID = DCSObject:getID() - return ObjectID - end - - return nil -end - ---- Destroys the OBJECT. --- @param #OBJECT self --- @return #nil The DCS Unit is not existing or alive. -function OBJECT:Destroy() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - - if DCSObject then - - DCSObject:destroy() - end - - return nil -end - - - - ---- This module contains the IDENTIFIABLE class. --- --- 1) @{#IDENTIFIABLE} class, extends @{Wrapper.Object#OBJECT} --- =============================================================== --- The @{#IDENTIFIABLE} class is a wrapper class to handle the DCS Identifiable objects: --- --- * Support all DCS Identifiable APIs. --- * Enhance with Identifiable specific APIs not in the DCS Identifiable API set. --- * Manage the "state" of the DCS Identifiable. --- --- 1.1) IDENTIFIABLE constructor: --- ------------------------------ --- The IDENTIFIABLE class provides the following functions to construct a IDENTIFIABLE instance: --- --- * @{#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. --- --- 1.2) IDENTIFIABLE methods: --- -------------------------- --- The following methods can be used to identify an identifiable object: --- --- * @{#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. --- * @{#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. --- * @{#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. --- * @{#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. --- * @{#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. --- * @{#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. --- --- --- === --- --- @module Identifiable - ---- The IDENTIFIABLE class --- @type IDENTIFIABLE --- @extends Wrapper.Object#OBJECT --- @field #string IdentifiableName The name of the identifiable. -IDENTIFIABLE = { - ClassName = "IDENTIFIABLE", - IdentifiableName = "", -} - -local _CategoryName = { - [Unit.Category.AIRPLANE] = "Airplane", - [Unit.Category.HELICOPTER] = "Helicoper", - [Unit.Category.GROUND_UNIT] = "Ground Identifiable", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - } - ---- Create a new IDENTIFIABLE from a DCSIdentifiable --- @param #IDENTIFIABLE self --- @param Dcs.DCSWrapper.Identifiable#Identifiable IdentifiableName The DCS Identifiable name --- @return #IDENTIFIABLE self -function IDENTIFIABLE:New( IdentifiableName ) - local self = BASE:Inherit( self, OBJECT:New( IdentifiableName ) ) - self:F2( IdentifiableName ) - self.IdentifiableName = IdentifiableName - return self -end - ---- Returns if the Identifiable is alive. --- @param #IDENTIFIABLE self --- @return #boolean true if Identifiable is alive. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:IsAlive() - self:F3( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableIsAlive = DCSIdentifiable:isExist() - return IdentifiableIsAlive - end - - return false -end - - - - ---- Returns DCS Identifiable object name. --- The function provides access to non-activated objects too. --- @param #IDENTIFIABLE self --- @return #string The name of the DCS Identifiable. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetName() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableName = self.IdentifiableName - return IdentifiableName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - ---- Returns the type name of the DCS Identifiable. --- @param #IDENTIFIABLE self --- @return #string The type name of the DCS Identifiable. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetTypeName() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableTypeName = DCSIdentifiable:getTypeName() - self:T3( IdentifiableTypeName ) - return IdentifiableTypeName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - ---- Returns category of the DCS Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Object#Object.Category The category ID -function IDENTIFIABLE:GetCategory() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - local ObjectCategory = DCSObject:getCategory() - self:T3( ObjectCategory ) - return ObjectCategory - end - - return nil -end - - ---- Returns the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. --- @param #IDENTIFIABLE self --- @return #string The DCS Identifiable Category Name -function IDENTIFIABLE:GetCategoryName() - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCategoryName = _CategoryName[ self:GetDesc().category ] - return IdentifiableCategoryName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Returns coalition of the Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The side of the coalition. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetCoalition() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCoalition = DCSIdentifiable:getCoalition() - self:T3( IdentifiableCoalition ) - return IdentifiableCoalition - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Returns country of the Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCScountry#country.id The country identifier. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetCountry() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCountry = DCSIdentifiable:getCountry() - self:T3( IdentifiableCountry ) - return IdentifiableCountry - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - - ---- Returns Identifiable descriptor. Descriptor type depends on Identifiable category. --- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Identifiable#Identifiable.Desc The Identifiable descriptor. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetDesc() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableDesc = DCSIdentifiable:getDesc() - self:T2( IdentifiableDesc ) - return IdentifiableDesc - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Gets the CallSign of the IDENTIFIABLE, which is a blank by default. --- @param #IDENTIFIABLE self --- @return #string The CallSign of the IDENTIFIABLE. -function IDENTIFIABLE:GetCallsign() - return '' -end - - - - - - - - - ---- This module contains the POSITIONABLE class. --- --- 1) @{Wrapper.Positionable#POSITIONABLE} class, extends @{Wrapper.Identifiable#IDENTIFIABLE} --- =========================================================== --- The @{Wrapper.Positionable#POSITIONABLE} class is a wrapper class to handle the POSITIONABLE objects: --- --- * Support all DCS APIs. --- * Enhance with POSITIONABLE specific APIs not in the DCS API set. --- * Manage the "state" of the POSITIONABLE. --- --- 1.1) POSITIONABLE constructor: --- ------------------------------ --- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: --- --- * @{Wrapper.Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. --- --- 1.2) POSITIONABLE methods: --- -------------------------- --- The following methods can be used to identify an measurable object: --- --- * @{Wrapper.Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. --- * @{Wrapper.Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. --- --- === --- --- @module Positionable - ---- The POSITIONABLE class --- @type POSITIONABLE --- @extends Wrapper.Identifiable#IDENTIFIABLE --- @field #string PositionableName The name of the measurable. -POSITIONABLE = { - ClassName = "POSITIONABLE", - PositionableName = "", -} - ---- A DCSPositionable --- @type DCSPositionable --- @field id_ The ID of the controllable in DCS - ---- Create a new POSITIONABLE from a DCSPositionable --- @param #POSITIONABLE self --- @param Dcs.DCSWrapper.Positionable#Positionable PositionableName The POSITIONABLE name --- @return #POSITIONABLE self -function POSITIONABLE:New( PositionableName ) - local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) - - return self -end - ---- Returns the @{Dcs.DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetPositionVec3() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePosition = DCSPositionable:getPosition() - self:T3( PositionablePosition ) - return PositionablePosition - end - - return nil -end - ---- Returns the @{Dcs.DCSTypes#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec2 The 2D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVec2() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - - local PositionableVec2 = {} - PositionableVec2.x = PositionableVec3.x - PositionableVec2.y = PositionableVec3.z - - self:T2( PositionableVec2 ) - return PositionableVec2 - end - - return nil -end - ---- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetPointVec2() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - - local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - - self:T2( PositionablePointVec2 ) - return PositionablePointVec2 - end - - return nil -end - - ---- Returns a random @{Dcs.DCSTypes#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetRandomVec3( Radius ) - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePointVec3 = DCSPositionable:getPosition().p - local PositionableRandomVec3 = {} - local angle = math.random() * math.pi*2; - PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius; - PositionableRandomVec3.y = PositionablePointVec3.y - PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius; - - self:T3( PositionableRandomVec3 ) - return PositionableRandomVec3 - end - - return nil -end - ---- Returns the @{Dcs.DCSTypes#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVec3() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - self:T3( PositionableVec3 ) - return PositionableVec3 - end - - return nil -end - ---- Returns the altitude of the POSITIONABLE. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Distance The altitude of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetAltitude() - self:F2() - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePointVec3 = DCSPositionable:getPoint() --Dcs.DCSTypes#Vec3 - return PositionablePointVec3.y - end - - return nil -end - ---- Returns if the Positionable is located above a runway. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #boolean true if Positionable is above a runway. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:IsAboveRunway() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - - local Vec2 = self:GetVec2() - local SurfaceType = land.getSurfaceType( Vec2 ) - local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - - self:T2( IsAboveRunway ) - return IsAboveRunway - end - - return nil -end - - - ---- Returns the POSITIONABLE heading in degrees. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #number The POSTIONABLE heading -function POSITIONABLE:GetHeading() - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - - local PositionablePosition = DCSPositionable:getPosition() - if PositionablePosition then - local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x ) - if PositionableHeading < 0 then - PositionableHeading = PositionableHeading + 2 * math.pi - end - PositionableHeading = PositionableHeading * 180 / math.pi - self:T2( PositionableHeading ) - return PositionableHeading - end - end - - return nil -end - - ---- Returns true if the POSITIONABLE is in the air. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #boolean true if in the air. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:InAir() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableInAir = DCSPositionable:inAir() - self:T3( PositionableInAir ) - return PositionableInAir - end - - return nil -end - - ---- Returns the POSITIONABLE velocity vector. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The velocity vector --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVelocity() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVelocityVec3 = DCSPositionable:getVelocity() - self:T3( PositionableVelocityVec3 ) - return PositionableVelocityVec3 - end - - return nil -end - ---- Returns the POSITIONABLE velocity in km/h. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #number The velocity in km/h --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVelocityKMH() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local VelocityVec3 = self:GetVelocity() - local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - local Velocity = Velocity * 3.6 -- now it is in km/h. - self:T3( Velocity ) - return Velocity - end - - return nil -end - ---- Returns a message with the callsign embedded (if there is one). --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. --- @return Core.Message#MESSAGE -function POSITIONABLE:GetMessage( Message, Duration, Name ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - Name = Name or self:GetTypeName() - return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. Name .. ")" ) - end - - return nil -end - ---- Send a message to all coalitions. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToAll( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToAll() - end - - return nil -end - ---- Send a message to a coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition ) - end - - return nil -end - - ---- Send a message to the red coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToRed( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToRed() - end - - return nil -end - ---- Send a message to the blue coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToBlue( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToBlue() - end - - return nil -end - ---- Send a message to a client. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param Wrapper.Client#CLIENT Client The client object receiving the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToClient( Message, Duration, Client, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToClient( Client ) - end - - return nil -end - ---- Send a message to a @{Group}. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param Wrapper.Group#GROUP MessageGroup The GROUP object receiving the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - if DCSObject:isExist() then - self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup ) - end - end - - return nil -end - ---- Send a message to the players in the @{Group}. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:Message( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToGroup( self ) - end - - return nil -end - - - - - ---- This module contains the CONTROLLABLE class. --- --- 1) @{Wrapper.Controllable#CONTROLLABLE} class, extends @{Wrapper.Positionable#POSITIONABLE} --- =========================================================== --- The @{Wrapper.Controllable#CONTROLLABLE} class is a wrapper class to handle the DCS Controllable objects: --- --- * Support all DCS Controllable APIs. --- * Enhance with Controllable specific APIs not in the DCS Controllable API set. --- * Handle local Controllable Controller. --- * Manage the "state" of the DCS Controllable. --- --- 1.1) CONTROLLABLE constructor --- ----------------------------- --- The CONTROLLABLE class provides the following functions to construct a CONTROLLABLE instance: --- --- * @{#CONTROLLABLE.New}(): Create a CONTROLLABLE instance. --- --- 1.2) CONTROLLABLE task methods --- ------------------------------ --- Several controllable task methods are available that help you to prepare tasks. --- These methods return a string consisting of the task description, which can then be given to either a @{Wrapper.Controllable#CONTROLLABLE.PushTask} or @{Wrapper.Controllable#SetTask} method to assign the task to the CONTROLLABLE. --- Tasks are specific for the category of the CONTROLLABLE, more specific, for AIR, GROUND or AIR and GROUND. --- Each task description where applicable indicates for which controllable category the task is valid. --- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. --- --- ### 1.2.1) Assigned task methods --- --- Assigned task methods make the controllable execute the task where the location of the (possible) targets of the task are known before being detected. --- This is different from the EnRoute tasks, where the targets of the task need to be detected before the task can be executed. --- --- Find below a list of the **assigned task** methods: --- --- * @{#CONTROLLABLE.TaskAttackControllable}: (AIR) Attack a Controllable. --- * @{#CONTROLLABLE.TaskAttackMapObject}: (AIR) Attacking the map object (building, structure, e.t.c). --- * @{#CONTROLLABLE.TaskAttackUnit}: (AIR) Attack the Unit. --- * @{#CONTROLLABLE.TaskBombing}: (AIR) Delivering weapon at the point on the ground. --- * @{#CONTROLLABLE.TaskBombingRunway}: (AIR) Delivering weapon on the runway. --- * @{#CONTROLLABLE.TaskEmbarking}: (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. --- * @{#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location. --- * @{#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne controllable. --- * @{#CONTROLLABLE.TaskFAC_AttackControllable}: (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. --- * @{#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire at a VEC2 point until ammunition is finished. --- * @{#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne controllable. --- * @{#CONTROLLABLE.TaskHold}: (GROUND) Hold ground controllable from moving. --- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable. --- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. --- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). --- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. --- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. --- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points. --- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point. --- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point. --- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone. --- * @{#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the controllable to an airbase. --- --- ### 1.2.2) EnRoute task methods --- --- EnRoute tasks require the targets of the task need to be detected by the controllable (using its sensors) before the task can be executed: --- --- * @{#CONTROLLABLE.EnRouteTaskAWACS}: (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- * @{#CONTROLLABLE.EnRouteTaskEngageControllable}: (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskEngageTargets}: (AIR) Engaging targets of defined types. --- * @{#CONTROLLABLE.EnRouteTaskEWR}: (AIR) Attack the Unit. --- * @{#CONTROLLABLE.EnRouteTaskFAC}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskFAC_EngageControllable}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskTanker}: (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- --- ### 1.2.3) Preparation task methods --- --- There are certain task methods that allow to tailor the task behaviour: --- --- * @{#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command. --- * @{#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks. --- * @{#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task. --- * @{#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition. --- --- ### 1.2.4) Obtain the mission from controllable templates --- --- Controllable templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a controllable and assign it to another: --- --- * @{#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. --- --- 1.3) CONTROLLABLE Command methods --- -------------------------- --- Controllable **command methods** prepare the execution of commands using the @{#CONTROLLABLE.SetCommand} method: --- --- * @{#CONTROLLABLE.CommandDoScript}: Do Script command. --- * @{#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command. --- --- 1.4) CONTROLLABLE Option methods --- ------------------------- --- Controllable **Option methods** change the behaviour of the Controllable while being alive. --- --- ### 1.4.1) Rule of Engagement: --- --- * @{#CONTROLLABLE.OptionROEWeaponFree} --- * @{#CONTROLLABLE.OptionROEOpenFire} --- * @{#CONTROLLABLE.OptionROEReturnFire} --- * @{#CONTROLLABLE.OptionROEEvadeFire} --- --- To check whether an ROE option is valid for a specific controllable, use: --- --- * @{#CONTROLLABLE.OptionROEWeaponFreePossible} --- * @{#CONTROLLABLE.OptionROEOpenFirePossible} --- * @{#CONTROLLABLE.OptionROEReturnFirePossible} --- * @{#CONTROLLABLE.OptionROEEvadeFirePossible} --- --- ### 1.4.2) Rule on thread: --- --- * @{#CONTROLLABLE.OptionROTNoReaction} --- * @{#CONTROLLABLE.OptionROTPassiveDefense} --- * @{#CONTROLLABLE.OptionROTEvadeFire} --- * @{#CONTROLLABLE.OptionROTVertical} --- --- To test whether an ROT option is valid for a specific controllable, use: --- --- * @{#CONTROLLABLE.OptionROTNoReactionPossible} --- * @{#CONTROLLABLE.OptionROTPassiveDefensePossible} --- * @{#CONTROLLABLE.OptionROTEvadeFirePossible} --- * @{#CONTROLLABLE.OptionROTVerticalPossible} --- --- === --- --- @module Controllable - ---- The CONTROLLABLE class --- @type CONTROLLABLE --- @extends Wrapper.Positionable#POSITIONABLE --- @field Dcs.DCSWrapper.Controllable#Controllable DCSControllable The DCS controllable class. --- @field #string ControllableName The name of the controllable. -CONTROLLABLE = { - ClassName = "CONTROLLABLE", - ControllableName = "", - WayPointFunctions = {}, -} - ---- Create a new CONTROLLABLE from a DCSControllable --- @param #CONTROLLABLE self --- @param Dcs.DCSWrapper.Controllable#Controllable ControllableName The DCS Controllable name --- @return #CONTROLLABLE self -function CONTROLLABLE:New( ControllableName ) - local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) - self:F2( ControllableName ) - self.ControllableName = ControllableName - - self.TaskScheduler = SCHEDULER:New( self ) - return self -end - --- DCS Controllable methods support. - ---- Get the controller for the CONTROLLABLE. --- @param #CONTROLLABLE self --- @return Dcs.DCSController#Controller -function CONTROLLABLE:_GetController() - self:F2( { self.ControllableName } ) - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local ControllableController = DCSControllable:getController() - self:T3( ControllableController ) - return ControllableController - end - - return nil -end - - - --- Tasks - ---- Popping current Task from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:PopCurrentTask() - self:F2() - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - Controller:popTask() - return self - end - - return nil -end - ---- Pushing Task on the queue from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:PushTask( DCSTask, WaitTime ) - self:F2() - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - - -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Controllable. - -- Controller:pushTask( DCSTask ) - - if WaitTime then - self.TaskScheduler:Schedule( Controller, Controller.pushTask, { DCSTask }, WaitTime ) - else - Controller:pushTask( DCSTask ) - end - - return self - end - - return nil -end - ---- Clearing the Task Queue and Setting the Task on the queue from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local Controller = self:_GetController() - self:E(Controller) - - -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Controllable. - -- Controller.setTask( Controller, DCSTask ) - - if not WaitTime then - Controller:setTask( DCSTask ) - else - self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime ) - end - - return self - end - - return nil -end - - ---- Return a condition section for a controlled task. --- @param #CONTROLLABLE self --- @param Dcs.DCSTime#Time time --- @param #string userFlag --- @param #boolean userFlagValue --- @param #string condition --- @param Dcs.DCSTime#Time duration --- @param #number lastWayPoint --- return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) - self:F2( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) - - local DCSStopCondition = {} - DCSStopCondition.time = time - DCSStopCondition.userFlag = userFlag - DCSStopCondition.userFlagValue = userFlagValue - DCSStopCondition.condition = condition - DCSStopCondition.duration = duration - DCSStopCondition.lastWayPoint = lastWayPoint - - self:T3( { DCSStopCondition } ) - return DCSStopCondition -end - ---- Return a Controlled Task taking a Task and a TaskCondition. --- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#Task DCSTask --- @param #DCSStopCondition DCSStopCondition --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition ) - self:F2( { DCSTask, DCSStopCondition } ) - - local DCSTaskControlled - - DCSTaskControlled = { - id = 'ControlledTask', - params = { - task = DCSTask, - stopCondition = DCSStopCondition - } - } - - self:T3( { DCSTaskControlled } ) - return DCSTaskControlled -end - ---- Return a Combo Task taking an array of Tasks. --- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#TaskArray DCSTasks Array of @{Dcs.DCSTasking.Task#Task} --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskCombo( DCSTasks ) - self:F2( { DCSTasks } ) - - local DCSTaskCombo - - DCSTaskCombo = { - id = 'ComboTask', - params = { - tasks = DCSTasks - } - } - - self:T3( { DCSTaskCombo } ) - return DCSTaskCombo -end - ---- Return a WrappedAction Task taking a Command. --- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index ) - self:F2( { DCSCommand } ) - - local DCSTaskWrappedAction - - DCSTaskWrappedAction = { - id = "WrappedAction", - enabled = true, - number = Index, - auto = false, - params = { - action = DCSCommand, - }, - } - - self:T3( { DCSTaskWrappedAction } ) - return DCSTaskWrappedAction -end - ---- Executes a command action --- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand --- @return #CONTROLLABLE self -function CONTROLLABLE:SetCommand( DCSCommand ) - self:F2( DCSCommand ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - Controller:setCommand( DCSCommand ) - return self - end - - return nil -end - ---- Perform a switch waypoint command --- @param #CONTROLLABLE self --- @param #number FromWayPoint --- @param #number ToWayPoint --- @return Dcs.DCSTasking.Task#Task --- @usage --- --- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class. --- HeliGroup = GROUP:FindByName( "Helicopter" ) --- --- --- Route the helicopter back to the FARP after 60 seconds. --- -- We use the SCHEDULER class to do this. --- SCHEDULER:New( nil, --- function( HeliGroup ) --- local CommandRTB = HeliGroup:CommandSwitchWayPoint( 2, 8 ) --- HeliGroup:SetCommand( CommandRTB ) --- end, { HeliGroup }, 90 --- ) -function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint ) - self:F2( { FromWayPoint, ToWayPoint } ) - - local CommandSwitchWayPoint = { - id = 'SwitchWaypoint', - params = { - fromWaypointIndex = FromWayPoint, - goToWaypointIndex = ToWayPoint, - }, - } - - self:T3( { CommandSwitchWayPoint } ) - return CommandSwitchWayPoint -end - ---- Perform stop route command --- @param #CONTROLLABLE self --- @param #boolean StopRoute --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:CommandStopRoute( StopRoute, Index ) - self:F2( { StopRoute, Index } ) - - local CommandStopRoute = { - id = 'StopRoute', - params = { - value = StopRoute, - }, - } - - self:T3( { CommandStopRoute } ) - return CommandStopRoute -end - - --- TASKS FOR AIR CONTROLLABLES - - ---- (AIR) Attack a Controllable. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- AttackControllable = { - -- id = 'AttackControllable', - -- params = { - -- groupId = Group.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend, - -- attackQty = number, - -- directionEnabled = boolean, - -- direction = Azimuth, - -- altitudeEnabled = boolean, - -- altitude = Distance, - -- attackQtyLimit = boolean, - -- } - -- } - - local DirectionEnabled = nil - if Direction then - DirectionEnabled = true - end - - local AltitudeEnabled = nil - if Altitude then - AltitudeEnabled = true - end - - local DCSTask - DCSTask = { id = 'AttackControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - directionEnabled = DirectionEnabled, - direction = Direction, - altitudeEnabled = AltitudeEnabled, - altitude = Altitude, - attackQtyLimit = AttackQtyLimit, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Attack the Unit. --- @param #CONTROLLABLE self --- @param Wrapper.Unit#UNIT AttackUnit The unit. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack ) - self:F2( { self.ControllableName, AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack } ) - - -- AttackUnit = { - -- id = 'AttackUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- controllableAttack = boolean, - -- } - -- } - - local DCSTask - DCSTask = { id = 'AttackUnit', - params = { - altitudeEnabled = false, - unitId = AttackUnit:GetID(), - attackQtyLimit = AttackQtyLimit or false, - attackQty = AttackQty or 1, - expend = WeaponExpend or "Auto", - altitude = 2000, - directionEnabled = false, - groupAttack = false, - weaponType = WeaponType or 1073741822, - direction = Direction or 0, - }, - }, - - self:E( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon at the point on the ground. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackControllable and AttackUnit tasks. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskBombing( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- Bombing = { --- id = 'Bombing', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'Bombing', - params = { - point = Vec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point to hold the position. --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.ControllableName, Point, Altitude, Speed } ) - - -- pattern = enum AI.Task.OribtPattern, - -- point = Vec2, - -- point2 = Vec2, - -- speed = Distance, - -- altitude = Distance - - local LandHeight = land.getHeight( Point ) - - self:T3( { LandHeight } ) - - local DCSTask = { id = 'Orbit', - params = { pattern = AI.Task.OrbitPattern.CIRCLE, - point = Point, - speed = Speed, - altitude = Altitude + LandHeight - } - } - - - -- local AITask = { id = 'ControlledTask', - -- params = { task = { id = 'Orbit', - -- params = { pattern = AI.Task.OrbitPattern.CIRCLE, - -- point = Point, - -- speed = Speed, - -- altitude = Altitude + LandHeight - -- } - -- }, - -- stopCondition = { duration = Duration - -- } - -- } - -- } - -- ) - - return DCSTask -end - ---- (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. --- @param #CONTROLLABLE self --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed ) - self:F2( { self.ControllableName, Altitude, Speed } ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local ControllablePoint = self:GetVec2() - return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed ) - end - - return nil -end - - - ---- (AIR) Hold position at the current position of the first unit of the controllable. --- @param #CONTROLLABLE self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskHoldPosition() - self:F2( { self.ControllableName } ) - - return self:TaskOrbitCircle( 30, 10 ) -end - - - - ---- (AIR) Attacking the map object (building, structure, e.t.c). --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point the map object is closest to. The distance between the point and the map object must not be greater than 2000 meters. Object id is not used here because Mission Editor doesn't support map object identificators. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackMapObject( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- AttackMapObject = { --- id = 'AttackMapObject', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'AttackMapObject', - params = { - point = Vec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon on the runway. --- @param #CONTROLLABLE self --- @param Wrapper.Airbase#AIRBASE Airbase Airbase to attack. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- BombingRunway = { --- id = 'BombingRunway', --- params = { --- runwayId = AirdromeId, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'BombingRunway', - params = { - point = Airbase:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Refueling from the nearest tanker. No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskRefueling() - self:F2( { self.ControllableName } ) - --- Refueling = { --- id = 'Refueling', --- params = {} --- } - - local DCSTask - DCSTask = { id = 'Refueling', - params = { - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR HELICOPTER) Landing at the ground. For helicopters only. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskLandAtVec2( Point, Duration ) - self:F2( { self.ControllableName, Point, Duration } ) - --- Land = { --- id= 'Land', --- params = { --- point = Vec2, --- durationFlag = boolean, --- duration = Time --- } --- } - - local DCSTask - if Duration and Duration > 0 then - DCSTask = { id = 'Land', - params = { - point = Point, - durationFlag = true, - duration = Duration, - }, - } - else - DCSTask = { id = 'Land', - params = { - point = Point, - durationFlag = false, - }, - } - end - - self:T3( DCSTask ) - return DCSTask -end - ---- (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint ) - self:F2( { self.ControllableName, Zone, Duration, RandomPoint } ) - - local Point - if RandomPoint then - Point = Zone:GetRandomVec2() - else - Point = Zone:GetVec2() - end - - local DCSTask = self:TaskLandAtVec2( Point, Duration ) - - self:T3( DCSTask ) - return DCSTask -end - - - ---- (AIR) Following another airborne controllable. --- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. --- If another controllable is on land the unit / controllable will orbit around. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE FollowControllable The controllable to be followed. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex ) - self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex } ) - --- Follow = { --- id = 'Follow', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number --- } --- } - - local LastWaypointIndexFlag = false - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { - id = 'Follow', - params = { - groupId = FollowControllable:GetID(), - pos = Vec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Escort another airborne controllable. --- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. --- The unit / controllable will also protect that controllable from threats of specified types. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. --- @param #number EngagementDistanceMax Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes ) - self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) - --- Escort = { --- id = 'Escort', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number, --- engagementDistMax = Distance, --- targetTypes = array of AttributeName, --- } --- } - - local LastWaypointIndexFlag = false - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Escort', - params = { - groupId = FollowControllable:GetID(), - pos = Vec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex, - engagementDistMax = EngagementDistance, - targetTypes = TargetTypes, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - --- GROUND TASKS - ---- (GROUND) Fire at a VEC2 point until ammunition is finished. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 The point to fire at. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone to deploy the fire at. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius ) - self:F2( { self.ControllableName, Vec2, Radius } ) - - -- FireAtPoint = { - -- id = 'FireAtPoint', - -- params = { - -- point = Vec2, - -- radius = Distance, - -- } - -- } - - local DCSTask - DCSTask = { id = 'FireAtPoint', - params = { - point = Vec2, - radius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Hold ground controllable from moving. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskHold() - self:F2( { self.ControllableName } ) - --- Hold = { --- id = 'Hold', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Hold', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- TASKS FOR AIRBORNE AND GROUND UNITS/CONTROLLABLES - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. --- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, Designation, Datalink } ) - --- FAC_AttackControllable = { --- id = 'FAC_AttackControllable', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_AttackControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - --- EN-ACT_ROUTE TASKS FOR AIRBORNE CONTROLLABLES - ---- (AIR) Engaging targets of defined types. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. --- @param #number Priority All enroute tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) - self:F2( { self.ControllableName, Distance, TargetTypes, Priority } ) - --- EngageTargets ={ --- id = 'EngageTargets', --- params = { --- maxDist = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargets', - params = { - maxDist = Distance, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR) Engaging a targets of defined types at circle-shaped zone. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the zone. --- @param Dcs.DCSTypes#Distance Radius Radius of the zone. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageTargets( Vec2, Radius, TargetTypes, Priority ) - self:F2( { self.ControllableName, Vec2, Radius, TargetTypes, Priority } ) - --- EngageTargetsInZone = { --- id = 'EngageTargetsInZone', --- params = { --- point = Vec2, --- zoneRadius = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargetsInZone', - params = { - point = Vec2, - zoneRadius = Radius, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.ControllableName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- EngageControllable = { - -- id = 'EngageControllable ', - -- params = { - -- groupId = Group.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend, - -- attackQty = number, - -- directionEnabled = boolean, - -- direction = Azimuth, - -- altitudeEnabled = boolean, - -- altitude = Distance, - -- attackQtyLimit = boolean, - -- priority = number, - -- } - -- } - - local DirectionEnabled = nil - if Direction then - DirectionEnabled = true - end - - local AltitudeEnabled = nil - if Altitude then - AltitudeEnabled = true - end - - local DCSTask - DCSTask = { id = 'EngageControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - directionEnabled = DirectionEnabled, - direction = Direction, - altitudeEnabled = AltitudeEnabled, - altitude = Altitude, - attackQtyLimit = AttackQtyLimit, - priority = Priority, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Attack the Unit. --- @param #CONTROLLABLE self --- @param Wrapper.Unit#UNIT AttackUnit The UNIT. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageUnit( AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack ) - self:F2( { self.ControllableName, AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack } ) - - -- EngageUnit = { - -- id = 'EngageUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- controllableAttack = boolean, - -- priority = number, - -- } - -- } - - local DCSTask - DCSTask = { id = 'EngageUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - controllableAttack = ControllableAttack, - priority = Priority, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskAWACS( ) - self:F2( { self.ControllableName } ) - --- AWACS = { --- id = 'AWACS', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'AWACS', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskTanker( ) - self:F2( { self.ControllableName } ) - --- Tanker = { --- id = 'Tanker', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Tanker', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for ground units/controllables - ---- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEWR( ) - self:F2( { self.ControllableName } ) - --- EWR = { --- id = 'EWR', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'EWR', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for airborne and ground units/controllables - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. --- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) - --- FAC_EngageControllable = { --- id = 'FAC_EngageControllable', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean, --- priority = number, --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_EngageControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - priority = Priority, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Radius The maximal distance from the FAC to a target. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority ) - self:F2( { self.ControllableName, Radius, Priority } ) - --- FAC = { --- id = 'FAC', --- params = { --- radius = Distance, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'FAC', - params = { - radius = Radius, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - - ---- (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. --- @param #number Duration The duration in seconds to wait. --- @param #CONTROLLABLE EmbarkingControllable The controllable to be embarked. --- @return Dcs.DCSTasking.Task#Task The DCS task structure -function CONTROLLABLE:TaskEmbarking( Point, Duration, EmbarkingControllable ) - self:F2( { self.ControllableName, Point, Duration, EmbarkingControllable.DCSControllable } ) - - local DCSTask - DCSTask = { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - controllablesForEmbarking = { EmbarkingControllable.ControllableID }, - durationFlag = true, - distributionFlag = false, - distribution = {}, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Embark to a Transport landed at a location. - ---- Move to a defined Vec2 Point, and embark to a controllable when arrived within a defined Radius. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. --- @param #number Radius The radius of the embarking zone around the Point. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) - self:F2( { self.ControllableName, Point, Radius } ) - - local DCSTask --Dcs.DCSTasking.Task#Task - DCSTask = { id = 'EmbarkToTransport', - params = { x = Point.x, - y = Point.y, - zoneRadius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR + GROUND) Return a mission task from a mission template. --- @param #CONTROLLABLE self --- @param #table TaskMission A table containing the mission task. --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskMission( TaskMission ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { TaskMission, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- Return a Misson task to follow a given route defined by Points. --- @param #CONTROLLABLE self --- @param #table Points A table of route points. --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskRoute( Points ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR + GROUND) Make the Controllable move to fly to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskRouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllablePoint = self:GetUnit( 1 ):GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.y - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - ---- (AIR + GROUND) Make the Controllable move to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskRouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllableVec3 = self:GetUnit( 1 ):GetVec3() - - local PointFrom = {} - PointFrom.x = ControllableVec3.x - PointFrom.y = ControllableVec3.z - PointFrom.alt = ControllableVec3.y - PointFrom.alt_type = "BARO" - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.z - PointTo.alt = Point.y - PointTo.alt_type = "BARO" - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - - - ---- Make the controllable to follow a given route. --- @param #CONTROLLABLE self --- @param #table GoPoints A table of Route Points. --- @return #CONTROLLABLE self -function CONTROLLABLE:Route( GoPoints ) - self:F2( GoPoints ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Points = routines.utils.deepCopy( GoPoints ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } - local Controller = self:_GetController() - --Controller.setTask( Controller, MissionTask ) - self.TaskScheduler:Schedule( Controller, Controller.setTask, { MissionTask }, 1 ) - return self - end - - return nil -end - - - ---- (AIR + GROUND) Route the controllable to a given zone. --- The controllable final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to route to. --- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Cone" - PointFrom.speed = 20 / 1.6 - - - local PointTo = {} - local ZonePoint - - if Randomize then - ZonePoint = Zone:GetRandomVec2() - else - ZonePoint = Zone:GetVec2() - end - - PointTo.x = ZonePoint.x - PointTo.y = ZonePoint.y - PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 20 / 1.6 - end - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self - end - - return nil -end - ---- (AIR) Return the Controllable to an @{Wrapper.Airbase#AIRBASE} --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Wrapper.Airbase#AIRBASE ReturnAirbase The @{Wrapper.Airbase#AIRBASE} to return to. --- @param #number Speed (optional) The speed. --- @return #string The route -function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed ) - self:F2( { ReturnAirbase, Speed } ) - --- Example --- [4] = --- { --- ["alt"] = 45, --- ["type"] = "Land", --- ["action"] = "Landing", --- ["alt_type"] = "BARO", --- ["formation_template"] = "", --- ["properties"] = --- { --- ["vnav"] = 1, --- ["scale"] = 0, --- ["angle"] = 0, --- ["vangle"] = 0, --- ["steer"] = 2, --- }, -- end of ["properties"] --- ["ETA"] = 527.81058817743, --- ["airdromeId"] = 12, --- ["y"] = 243127.2973737, --- ["x"] = -5406.2803440839, --- ["name"] = "DictKey_WptName_53", --- ["speed"] = 138.88888888889, --- ["ETA_locked"] = false, --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] --- ["speed_locked"] = true, --- }, -- end of [4] - - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - local ControllableVelocity = self:GetMaxVelocity() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = ControllableVelocity - - - local PointTo = {} - local AirbasePoint = ReturnAirbase:GetVec2() - - PointTo.x = AirbasePoint.x - PointTo.y = AirbasePoint.y - PointTo.type = "Land" - PointTo.action = "Landing" - PointTo.airdromeId = ReturnAirbase:GetID()-- Airdrome ID - self:T(PointTo.airdromeId) - --PointTo.alt = 0 - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - local Route = { points = Points, } - - return Route - end - - return nil -end - --- Commands - ---- Do Script command --- @param #CONTROLLABLE self --- @param #string DoScript --- @return #DCSCommand -function CONTROLLABLE:CommandDoScript( DoScript ) - - local DCSDoScript = { - id = "Script", - params = { - command = DoScript, - }, - } - - self:T3( DCSDoScript ) - return DCSDoScript -end - - ---- Return the mission template of the controllable. --- @param #CONTROLLABLE self --- @return #table The MissionTemplate --- TODO: Rework the method how to retrieve a template ... -function CONTROLLABLE:GetTaskMission() - self:F2( self.ControllableName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template ) -end - ---- Return the mission route of the controllable. --- @param #CONTROLLABLE self --- @return #table The mission route defined by points. -function CONTROLLABLE:GetTaskRoute() - self:F2( self.ControllableName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template.route.points ) -end - ---- Return the route of a controllable by using the @{Core.Database#DATABASE} class. --- @param #CONTROLLABLE self --- @param #number Begin The route point from where the copy will start. The base route point is 0. --- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. --- @param #boolean Randomize Randomization of the route, when true. --- @param #number Radius When randomization is on, the randomization is within the radius. -function CONTROLLABLE:CopyRoute( Begin, End, Randomize, Radius ) - self:F2( { Begin, End } ) - - local Points = {} - - -- Could be a Spawned Controllable - local ControllableName = string.match( self:GetName(), ".*#" ) - if ControllableName then - ControllableName = ControllableName:sub( 1, -2 ) - else - ControllableName = self:GetName() - end - - self:T3( { ControllableName } ) - - local Template = _DATABASE.Templates.Controllables[ControllableName].Template - - if Template then - if not Begin then - Begin = 0 - end - if not End then - End = 0 - end - - for TPointID = Begin + 1, #Template.route.points - End do - if Template.route.points[TPointID] then - Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) - if Randomize then - if not Radius then - Radius = 500 - end - Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) - Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) - end - end - end - return Points - else - error( "Template not found for Controllable : " .. ControllableName ) - end - - return nil -end - - ---- Return the detected targets of the controllable. --- The optional parametes specify the detection methods that can be applied. --- If no detection method is given, the detection will use all the available methods by default. --- @param Wrapper.Controllable#CONTROLLABLE self --- @param #boolean DetectVisual (optional) --- @param #boolean DetectOptical (optional) --- @param #boolean DetectRadar (optional) --- @param #boolean DetectIRST (optional) --- @param #boolean DetectRWR (optional) --- @param #boolean DetectDLINK (optional) --- @return #table DetectedTargets -function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) - self:F2( self.ControllableName ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local DetectionVisual = ( DetectVisual and DetectVisual == true ) and Controller.Detection.VISUAL or nil - local DetectionOptical = ( DetectOptical and DetectOptical == true ) and Controller.Detection.OPTICAL or nil - local DetectionRadar = ( DetectRadar and DetectRadar == true ) and Controller.Detection.RADAR or nil - local DetectionIRST = ( DetectIRST and DetectIRST == true ) and Controller.Detection.IRST or nil - local DetectionRWR = ( DetectRWR and DetectRWR == true ) and Controller.Detection.RWR or nil - local DetectionDLINK = ( DetectDLINK and DetectDLINK == true ) and Controller.Detection.DLINK or nil - - - return self:_GetController():getDetectedTargets( DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK ) - end - - return nil -end - -function CONTROLLABLE:IsTargetDetected( DCSObject ) - self:F2( self.ControllableName ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - - local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity - = self:_GetController().isTargetDetected( self:_GetController(), DCSObject, - Controller.Detection.VISUAL, - Controller.Detection.OPTIC, - Controller.Detection.RADAR, - Controller.Detection.IRST, - Controller.Detection.RWR, - Controller.Detection.DLINK - ) - return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity - end - - return nil -end - --- Options - ---- Can the CONTROLLABLE hold their weapons? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEHoldFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Holding weapons. --- @param Wrapper.Controllable#CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:OptionROEHoldFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.WEAPON_HOLD ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.WEAPON_HOLD ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack returning on enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEReturnFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Return fire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEReturnFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.RETURN_FIRE ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.RETURN_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack designated targets? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEOpenFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Openfire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEOpenFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.OPEN_FIRE ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.OPEN_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack targets of opportunity? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEWeaponFreePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Weapon free. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEWeaponFree() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE ignore enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTNoReactionPossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- No evasion on enemy threats. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTNoReaction() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade using passive defenses? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTPassiveDefensePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Evasion passive defense. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTPassiveDefense() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENCE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade on enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTEvadeFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTEvadeFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade on fire using vertical manoeuvres? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTVerticalPossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire using vertical manoeuvres. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTVertical() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - end - - return self - end - - return nil -end - ---- Retrieve the controllable mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Wrapper.Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. --- Use the method @{Controllable@CONTROLLABLE:WayPointExecute) to start the execution of the new mission plan. --- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED! --- @param #CONTROLLABLE self --- @param #table WayPoints If WayPoints is given, then use the route. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointInitialize( WayPoints ) - self:F( { WayPoints } ) - - if WayPoints then - self.WayPoints = WayPoints - else - self.WayPoints = self:GetTaskRoute() - end - - return self -end - ---- Get the current WayPoints set with the WayPoint functions( Note that the WayPoints can be nil, although there ARE waypoints). --- @param #CONTROLLABLE self --- @return #table WayPoints If WayPoints is given, then return the WayPoints structure. -function CONTROLLABLE:GetWayPoints() - self:F( ) - - if self.WayPoints then - return self.WayPoints - end - - return nil -end - ---- Registers a waypoint function that will be executed when the controllable moves over the WayPoint. --- @param #CONTROLLABLE self --- @param #number WayPoint The waypoint number. Note that the start waypoint on the route is WayPoint 1! --- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions. --- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... ) - self:F2( { WayPoint, WayPointIndex, WayPointFunction } ) - - table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex ) - self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPoint, WayPointIndex, WayPointFunction, arg ) - return self -end - - -function CONTROLLABLE:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) - self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) - - local DCSTask - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) " - - if FunctionArguments and #FunctionArguments > 0 then - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, " .. table.concat( FunctionArguments, "," ) .. ")" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )" - end - - DCSTask = self:TaskWrappedAction( - self:CommandDoScript( - table.concat( DCSScript ) - ), WayPointIndex - ) - - self:T3( DCSTask ) - - return DCSTask - -end - ---- Executes the WayPoint plan. --- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint. --- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1! --- @param #CONTROLLABLE self --- @param #number WayPoint The WayPoint from where to execute the mission. --- @param #number WaitTime The amount seconds to wait before initiating the mission. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime ) - self:F( { WayPoint, WaitTime } ) - - if not WayPoint then - WayPoint = 1 - end - - -- When starting the mission from a certain point, the TaskPoints need to be deleted before the given WayPoint. - for TaskPointID = 1, WayPoint - 1 do - table.remove( self.WayPoints, 1 ) - end - - self:T3( self.WayPoints ) - - self:SetTask( self:TaskRoute( self.WayPoints ), WaitTime ) - - return self -end - --- Message APIs - - ---- This module contains the GROUP class. --- --- 1) @{Wrapper.Group#GROUP} class, extends @{Wrapper.Controllable#CONTROLLABLE} --- ============================================================= --- The @{Wrapper.Group#GROUP} class is a wrapper class to handle the DCS Group objects: --- --- * Support all DCS Group APIs. --- * Enhance with Group specific APIs not in the DCS Group API set. --- * Handle local Group Controller. --- * Manage the "state" of the DCS Group. --- --- **IMPORTANT: ONE SHOULD NEVER SANATIZE these GROUP OBJECT REFERENCES! (make the GROUP object references nil).** --- --- 1.1) GROUP reference methods --- ----------------------- --- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). --- --- The GROUP class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the DCS Group or the DCS GroupName. --- --- Another thing to know is that GROUP objects do not "contain" the DCS Group object. --- The GROUP methods will reference the DCS Group object by name when it is needed during API execution. --- If the DCS Group object does not exist or is nil, the GROUP methods will return nil and log an exception in the DCS.log file. --- --- The GROUP class provides the following functions to retrieve quickly the relevant GROUP instance: --- --- * @{#GROUP.Find}(): Find a GROUP instance from the _DATABASE object using a DCS Group object. --- * @{#GROUP.FindByName}(): Find a GROUP instance from the _DATABASE object using a DCS Group name. --- --- 1.2) GROUP task methods --- ----------------------- --- Several group task methods are available that help you to prepare tasks. --- These methods return a string consisting of the task description, which can then be given to either a --- @{Wrapper.Controllable#CONTROLLABLE.PushTask} or @{Wrapper.Controllable#CONTROLLABLE.SetTask} method to assign the task to the GROUP. --- Tasks are specific for the category of the GROUP, more specific, for AIR, GROUND or AIR and GROUND. --- Each task description where applicable indicates for which group category the task is valid. --- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. --- --- ### 1.2.1) Assigned task methods --- --- Assigned task methods make the group execute the task where the location of the (possible) targets of the task are known before being detected. --- This is different from the EnRoute tasks, where the targets of the task need to be detected before the task can be executed. --- --- Find below a list of the **assigned task** methods: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackGroup}: (AIR) Attack a Group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackMapObject}: (AIR) Attacking the map object (building, structure, e.t.c). --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackUnit}: (AIR) Attack the Unit. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskBombing}: (Wrapper.Controllable#CONTROLLABLEDelivering weapon at the point on the ground. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskBombingRunway}: (AIR) Delivering weapon on the runway. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEmbarking}: (AIR) Move the group to a Vec2 Point, wait for a defined duration and embark a group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFAC_AttackGroup}: (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire at a VEC2 point until ammunition is finished. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskHold}: (GROUND) Hold ground group from moving. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the group at a @{Core.Zone#ZONE_RADIUS). --- * @{Wrapper.Controllable#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the group at a specified alititude. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Group move to a given point. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Group move to a given point. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the group to a given zone. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the group to an airbase. --- --- ### 1.2.2) EnRoute task methods --- --- EnRoute tasks require the targets of the task need to be detected by the group (using its sensors) before the task can be executed: --- --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskAWACS}: (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEngageGroup}: (AIR) Engaging a group. The task does not assign the target group to the unit/group to attack now; it just allows the unit/group to engage the target group as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEngageTargets}: (AIR) Engaging targets of defined types. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEWR}: (AIR) Attack the Unit. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskFAC}: (AIR + GROUND) The task makes the group/unit a FAC and lets the FAC to choose a targets (enemy ground group) around as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskFAC_EngageGroup}: (AIR + GROUND) The task makes the group/unit a FAC and lets the FAC to choose the target (enemy ground group) as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskTanker}: (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- --- ### 1.2.3) Preparation task methods --- --- There are certain task methods that allow to tailor the task behaviour: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition. --- --- ### 1.2.4) Obtain the mission from group templates --- --- Group templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a group and assign it to another: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. --- --- 1.3) GROUP Command methods --- -------------------------- --- Group **command methods** prepare the execution of commands using the @{Wrapper.Controllable#CONTROLLABLE.SetCommand} method: --- --- * @{Wrapper.Controllable#CONTROLLABLE.CommandDoScript}: Do Script command. --- * @{Wrapper.Controllable#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command. --- --- 1.4) GROUP Option methods --- ------------------------- --- Group **Option methods** change the behaviour of the Group while being alive. --- --- ### 1.4.1) Rule of Engagement: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEWeaponFree} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEOpenFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEReturnFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEEvadeFire} --- --- To check whether an ROE option is valid for a specific group, use: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEWeaponFreePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEOpenFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEReturnFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEEvadeFirePossible} --- --- ### 1.4.2) Rule on thread: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTNoReaction} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTPassiveDefense} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTEvadeFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTVertical} --- --- To test whether an ROT option is valid for a specific group, use: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTNoReactionPossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTPassiveDefensePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTEvadeFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTVerticalPossible} --- --- 1.5) GROUP Zone validation methods --- ---------------------------------- --- The group can be validated whether it is completely, partly or not within a @{Zone}. --- Use the following Zone validation methods on the group: --- --- * @{#GROUP.IsCompletelyInZone}: Returns true if all units of the group are within a @{Zone}. --- * @{#GROUP.IsPartlyInZone}: Returns true if some units of the group are within a @{Zone}. --- * @{#GROUP.IsNotInZone}: Returns true if none of the group units of the group are within a @{Zone}. --- --- The zone can be of any @{Zone} class derived from @{Core.Zone#ZONE_BASE}. So, these methods are polymorphic to the zones tested on. --- --- @module Group --- @author FlightControl - ---- The GROUP class --- @type GROUP --- @extends Wrapper.Controllable#CONTROLLABLE --- @field #string GroupName The name of the group. -GROUP = { - ClassName = "GROUP", -} - ---- Create a new GROUP from a DCSGroup --- @param #GROUP self --- @param Dcs.DCSWrapper.Group#Group GroupName The DCS Group name --- @return #GROUP self -function GROUP:Register( GroupName ) - local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) - self:F2( GroupName ) - self.GroupName = GroupName - return self -end - --- Reference methods. - ---- Find the GROUP wrapper class instance using the DCS Group. --- @param #GROUP self --- @param Dcs.DCSWrapper.Group#Group DCSGroup The DCS Group. --- @return #GROUP The GROUP. -function GROUP:Find( DCSGroup ) - - local GroupName = DCSGroup:getName() -- Wrapper.Group#GROUP - local GroupFound = _DATABASE:FindGroup( GroupName ) - return GroupFound -end - ---- Find the created GROUP using the DCS Group Name. --- @param #GROUP self --- @param #string GroupName The DCS Group Name. --- @return #GROUP The GROUP. -function GROUP:FindByName( GroupName ) - - local GroupFound = _DATABASE:FindGroup( GroupName ) - return GroupFound -end - --- DCS Group methods support. - ---- Returns the DCS Group. --- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group The DCS Group. -function GROUP:GetDCSObject() - local DCSGroup = Group.getByName( self.GroupName ) - - if DCSGroup then - return DCSGroup - end - - return nil -end - - ---- Returns if the DCS Group is alive. --- When the group exists at run-time, this method will return true, otherwise false. --- @param #GROUP self --- @return #boolean true if the DCS Group is alive. -function GROUP:IsAlive() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupIsAlive = DCSGroup:isExist() - self:T3( GroupIsAlive ) - return GroupIsAlive - end - - return nil -end - ---- Destroys the DCS Group and all of its DCS Units. --- Note that this destroy method also raises a destroy event at run-time. --- So all event listeners will catch the destroy event of this DCS Group. --- @param #GROUP self -function GROUP:Destroy() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - self:CreateEventCrash( timer.getTime(), UnitData ) - end - DCSGroup:destroy() - DCSGroup = nil - end - - return nil -end - ---- Returns category of the DCS Group. --- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group.Category The category ID -function GROUP:GetCategory() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T3( GroupCategory ) - return GroupCategory - end - - return nil -end - ---- Returns the category name of the DCS Group. --- @param #GROUP self --- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship -function GROUP:GetCategoryName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local CategoryNames = { - [Group.Category.AIRPLANE] = "Airplane", - [Group.Category.HELICOPTER] = "Helicopter", - [Group.Category.GROUND] = "Ground Unit", - [Group.Category.SHIP] = "Ship", - } - local GroupCategory = DCSGroup:getCategory() - self:T3( GroupCategory ) - - return CategoryNames[GroupCategory] - end - - return nil -end - - ---- Returns the coalition of the DCS Group. --- @param #GROUP self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The coalition side of the DCS Group. -function GROUP:GetCoalition() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCoalition = DCSGroup:getCoalition() - self:T3( GroupCoalition ) - return GroupCoalition - end - - return nil -end - ---- Returns the country of the DCS Group. --- @param #GROUP self --- @return Dcs.DCScountry#country.id The country identifier. --- @return #nil The DCS Group is not existing or alive. -function GROUP:GetCountry() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCountry = DCSGroup:getUnit(1):getCountry() - self:T3( GroupCountry ) - return GroupCountry - end - - return nil -end - ---- Returns the UNIT wrapper class with number UnitNumber. --- If the underlying DCS Unit does not exist, the method will return nil. . --- @param #GROUP self --- @param #number UnitNumber The number of the UNIT wrapper class to be returned. --- @return Wrapper.Unit#UNIT The UNIT wrapper class. -function GROUP:GetUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) - self:T3( UnitFound.UnitName ) - self:T2( UnitFound ) - return UnitFound - end - - return nil -end - ---- Returns the DCS Unit with number UnitNumber. --- If the underlying DCS Unit does not exist, the method will return nil. . --- @param #GROUP self --- @param #number UnitNumber The number of the DCS Unit to be returned. --- @return Dcs.DCSWrapper.Unit#Unit The DCS Unit. -function GROUP:GetDCSUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) - self:T3( DCSUnitFound ) - return DCSUnitFound - end - - return nil -end - ---- Returns current size of the DCS Group. --- If some of the DCS Units of the DCS Group are destroyed the size of the DCS Group is changed. --- @param #GROUP self --- @return #number The DCS Group size. -function GROUP:GetSize() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupSize = DCSGroup:getSize() - self:T3( GroupSize ) - return GroupSize - end - - return nil -end - ---- ---- Returns the initial size of the DCS Group. --- If some of the DCS Units of the DCS Group are destroyed, the initial size of the DCS Group is unchanged. --- @param #GROUP self --- @return #number The DCS Group initial size. -function GROUP:GetInitialSize() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupInitialSize = DCSGroup:getInitialSize() - self:T3( GroupInitialSize ) - return GroupInitialSize - end - - return nil -end - ---- Returns the UNITs wrappers of the DCS Units of the DCS Group. --- @param #GROUP self --- @return #table The UNITs wrappers. -function GROUP:GetUnits() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnits = DCSGroup:getUnits() - local Units = {} - for Index, UnitData in pairs( DCSUnits ) do - Units[#Units+1] = UNIT:Find( UnitData ) - end - self:T3( Units ) - return Units - end - - return nil -end - - ---- Returns the DCS Units of the DCS Group. --- @param #GROUP self --- @return #table The DCS Units. -function GROUP:GetDCSUnits() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnits = DCSGroup:getUnits() - self:T3( DCSUnits ) - return DCSUnits - end - - return nil -end - - ---- Activates a GROUP. --- @param #GROUP self -function GROUP:Activate() - self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSObject() ) - return self:GetDCSObject() -end - - ---- Gets the type name of the group. --- @param #GROUP self --- @return #string The type name of the group. -function GROUP:GetTypeName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupTypeName = DCSGroup:getUnit(1):getTypeName() - self:T3( GroupTypeName ) - return( GroupTypeName ) - end - - return nil -end - ---- Gets the CallSign of the first DCS Unit of the DCS Group. --- @param #GROUP self --- @return #string The CallSign of the first DCS Unit of the DCS Group. -function GROUP:GetCallsign() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCallSign = DCSGroup:getUnit(1):getCallsign() - self:T3( GroupCallSign ) - return GroupCallSign - end - - return nil -end - ---- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. --- @param #GROUP self --- @return Dcs.DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. -function GROUP:GetVec2() - self:F2( self.GroupName ) - - local UnitPoint = self:GetUnit(1) - UnitPoint:GetVec2() - local GroupPointVec2 = UnitPoint:GetVec2() - self:T3( GroupPointVec2 ) - return GroupPointVec2 -end - ---- Returns the current Vec3 vector of the first DCS Unit in the GROUP. --- @return Dcs.DCSTypes#Vec3 Current Vec3 of the first DCS Unit of the GROUP. -function GROUP:GetVec3() - self:F2( self.GroupName ) - - local GroupVec3 = self:GetUnit(1):GetVec3() - self:T3( GroupVec3 ) - return GroupVec3 -end - - - --- Is Zone Functions - ---- Returns true if all units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsCompletelyInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - -- TODO: Rename IsPointVec3InZone to IsVec3InZone - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - else - return false - end - end - - return true -end - ---- Returns true if some units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsPartlyInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - return true - end - end - - return false -end - ---- Returns true if none of the group units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsNotInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - return false - end - end - - return true -end - ---- Returns if the group is of an air category. --- If the group is a helicopter or a plane, then this method will return true, otherwise false. --- @param #GROUP self --- @return #boolean Air category evaluation result. -function GROUP:IsAir() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER - self:T3( IsAirResult ) - return IsAirResult - end - - return nil -end - ---- Returns if the DCS Group contains Helicopters. --- @param #GROUP self --- @return #boolean true if DCS Group contains Helicopters. -function GROUP:IsHelicopter() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.HELICOPTER - end - - return nil -end - ---- Returns if the DCS Group contains AirPlanes. --- @param #GROUP self --- @return #boolean true if DCS Group contains AirPlanes. -function GROUP:IsAirPlane() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.AIRPLANE - end - - return nil -end - ---- Returns if the DCS Group contains Ground troops. --- @param #GROUP self --- @return #boolean true if DCS Group contains Ground troops. -function GROUP:IsGround() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.GROUND - end - - return nil -end - ---- Returns if the DCS Group contains Ships. --- @param #GROUP self --- @return #boolean true if DCS Group contains Ships. -function GROUP:IsShip() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.SHIP - end - - return nil -end - ---- Returns if all units of the group are on the ground or landed. --- If all units of this group are on the ground, this function will return true, otherwise false. --- @param #GROUP self --- @return #boolean All units on the ground result. -function GROUP:AllOnGround() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local AllOnGroundResult = true - - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - if UnitData:inAir() then - AllOnGroundResult = false - end - end - - self:T3( AllOnGroundResult ) - return AllOnGroundResult - end - - return nil -end - ---- Returns the current maximum velocity of the group. --- Each unit within the group gets evaluated, and the maximum velocity (= the unit which is going the fastest) is returned. --- @param #GROUP self --- @return #number Maximum velocity found. -function GROUP:GetMaxVelocity() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupVelocityMax = 0 - - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - - local UnitVelocityVec3 = UnitData:getVelocity() - local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) - - if UnitVelocity > GroupVelocityMax then - GroupVelocityMax = UnitVelocity - end - end - - return GroupVelocityMax - end - - return nil -end - ---- Returns the current minimum height of the group. --- Each unit within the group gets evaluated, and the minimum height (= the unit which is the lowest elevated) is returned. --- @param #GROUP self --- @return #number Minimum height found. -function GROUP:GetMinHeight() - self:F2() - -end - ---- Returns the current maximum height of the group. --- Each unit within the group gets evaluated, and the maximum height (= the unit which is the highest elevated) is returned. --- @param #GROUP self --- @return #number Maximum height found. -function GROUP:GetMaxHeight() - self:F2() - -end - --- SPAWNING - ---- Respawn the @{GROUP} using a (tweaked) template of the Group. --- The template must be retrieved with the @{Wrapper.Group#GROUP.GetTemplate}() function. --- The template contains all the definitions as declared within the mission file. --- To understand templates, do the following: --- --- * unpack your .miz file into a directory using 7-zip. --- * browse in the directory created to the file **mission**. --- * open the file and search for the country group definitions. --- --- Your group template will contain the fields as described within the mission file. --- --- This function will: --- --- * Get the current position and heading of the group. --- * When the group is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. --- * Then it will destroy the current alive group. --- * And it will respawn the group using your new template definition. --- @param Wrapper.Group#GROUP self --- @param #table Template The template of the Group retrieved with GROUP:GetTemplate() -function GROUP:Respawn( Template ) - - local Vec3 = self:GetVec3() - Template.x = Vec3.x - Template.y = Vec3.z - --Template.x = nil - --Template.y = nil - - self:E( #Template.units ) - for UnitID, UnitData in pairs( self:GetUnits() ) do - local GroupUnit = UnitData -- Wrapper.Unit#UNIT - self:E( GroupUnit:GetName() ) - if GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - Template.units[UnitID].alt = GroupUnitVec3.y - Template.units[UnitID].x = GroupUnitVec3.x - Template.units[UnitID].y = GroupUnitVec3.z - Template.units[UnitID].heading = GroupUnitHeading - self:E( { UnitID, Template.units[UnitID], Template.units[UnitID] } ) - end - end - - self:Destroy() - _DATABASE:Spawn( Template ) -end - ---- Returns the group template from the @{DATABASE} (_DATABASE object). --- @param #GROUP self --- @return #table -function GROUP:GetTemplate() - local GroupName = self:GetName() - self:E( GroupName ) - return _DATABASE:GetGroupTemplate( GroupName ) -end - ---- Sets the controlled status in a Template. --- @param #GROUP self --- @param #boolean Controlled true is controlled, false is uncontrolled. --- @return #table -function GROUP:SetTemplateControlled( Template, Controlled ) - Template.uncontrolled = not Controlled - return Template -end - ---- Sets the CountryID of the group in a Template. --- @param #GROUP self --- @param Dcs.DCScountry#country.id CountryID The country ID. --- @return #table -function GROUP:SetTemplateCountry( Template, CountryID ) - Template.CountryID = CountryID - return Template -end - ---- Sets the CoalitionID of the group in a Template. --- @param #GROUP self --- @param Dcs.DCSCoalitionWrapper.Object#coalition.side CoalitionID The coalition ID. --- @return #table -function GROUP:SetTemplateCoalition( Template, CoalitionID ) - Template.CoalitionID = CoalitionID - return Template -end - - - - ---- Return the mission template of the group. --- @param #GROUP self --- @return #table The MissionTemplate -function GROUP:GetTaskMission() - self:F2( self.GroupName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template ) -end - ---- Return the mission route of the group. --- @param #GROUP self --- @return #table The mission route defined by points. -function GROUP:GetTaskRoute() - self:F2( self.GroupName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points ) -end - ---- Return the route of a group by using the @{Core.Database#DATABASE} class. --- @param #GROUP self --- @param #number Begin The route point from where the copy will start. The base route point is 0. --- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. --- @param #boolean Randomize Randomization of the route, when true. --- @param #number Radius When randomization is on, the randomization is within the radius. -function GROUP:CopyRoute( Begin, End, Randomize, Radius ) - self:F2( { Begin, End } ) - - local Points = {} - - -- Could be a Spawned Group - local GroupName = string.match( self:GetName(), ".*#" ) - if GroupName then - GroupName = GroupName:sub( 1, -2 ) - else - GroupName = self:GetName() - end - - self:T3( { GroupName } ) - - local Template = _DATABASE.Templates.Groups[GroupName].Template - - if Template then - if not Begin then - Begin = 0 - end - if not End then - End = 0 - end - - for TPointID = Begin + 1, #Template.route.points - End do - if Template.route.points[TPointID] then - Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) - if Randomize then - if not Radius then - Radius = 500 - end - Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) - Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) - end - end - end - return Points - else - error( "Template not found for Group : " .. GroupName ) - end - - return nil -end - ---- Calculate the maxium A2G threat level of the Group. --- @param #GROUP self -function GROUP:CalculateThreatLevelA2G() - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( self:GetUnits() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - return MaxThreatLevelA2G -end - - ---- This module contains the UNIT class. --- --- 1) @{#UNIT} class, extends @{Wrapper.Controllable#CONTROLLABLE} --- =========================================================== --- The @{#UNIT} class is a wrapper class to handle the DCS Unit objects: --- --- * Support all DCS Unit APIs. --- * Enhance with Unit specific APIs not in the DCS Unit API set. --- * Handle local Unit Controller. --- * Manage the "state" of the DCS Unit. --- --- --- 1.1) UNIT reference methods --- ---------------------- --- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Unit objects are spawned (using the @{SPAWN} class). --- --- The UNIT class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference --- using the DCS Unit or the DCS UnitName. --- --- Another thing to know is that UNIT objects do not "contain" the DCS Unit object. --- The UNIT methods will reference the DCS Unit object by name when it is needed during API execution. --- If the DCS Unit object does not exist or is nil, the UNIT methods will return nil and log an exception in the DCS.log file. --- --- The UNIT class provides the following functions to retrieve quickly the relevant UNIT instance: --- --- * @{#UNIT.Find}(): Find a UNIT instance from the _DATABASE object using a DCS Unit object. --- * @{#UNIT.FindByName}(): Find a UNIT instance from the _DATABASE object using a DCS Unit name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these UNIT OBJECT REFERENCES! (make the UNIT object references nil). --- --- 1.2) DCS UNIT APIs --- ------------------ --- The DCS Unit APIs are used extensively within MOOSE. The UNIT class has for each DCS Unit API a corresponding method. --- To be able to distinguish easily in your code the difference between a UNIT API call and a DCS Unit API call, --- the first letter of the method is also capitalized. So, by example, the DCS Unit method @{Dcs.DCSWrapper.Unit#Unit.getName}() --- is implemented in the UNIT class as @{#UNIT.GetName}(). --- --- 1.3) Smoke, Flare Units --- ----------------------- --- The UNIT class provides methods to smoke or flare units easily. --- The @{#UNIT.SmokeBlue}(), @{#UNIT.SmokeGreen}(),@{#UNIT.SmokeOrange}(), @{#UNIT.SmokeRed}(), @{#UNIT.SmokeRed}() methods --- will smoke the unit in the corresponding color. Note that smoking a unit is done at the current position of the DCS Unit. --- When the DCS Unit moves for whatever reason, the smoking will still continue! --- The @{#UNIT.FlareGreen}(), @{#UNIT.FlareRed}(), @{#UNIT.FlareWhite}(), @{#UNIT.FlareYellow}() --- methods will fire off a flare in the air with the corresponding color. Note that a flare is a one-off shot and its effect is of very short duration. --- --- 1.4) Location Position, Point --- ----------------------------- --- The UNIT class provides methods to obtain the current point or position of the DCS Unit. --- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively. --- If you want to obtain the complete **3D position** including ori�ntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively. --- --- 1.5) Test if alive --- ------------------ --- The @{#UNIT.IsAlive}(), @{#UNIT.IsActive}() methods determines if the DCS Unit is alive, meaning, it is existing and active. --- --- 1.6) Test for proximity --- ----------------------- --- The UNIT class contains methods to test the location or proximity against zones or other objects. --- --- ### 1.6.1) Zones --- To test whether the Unit is within a **zone**, use the @{#UNIT.IsInZone}() or the @{#UNIT.IsNotInZone}() methods. Any zone can be tested on, but the zone must be derived from @{Core.Zone#ZONE_BASE}. --- --- ### 1.6.2) Units --- Test if another DCS Unit is within a given radius of the current DCS Unit, use the @{#UNIT.OtherUnitInRadius}() method. --- --- @module Unit --- @author FlightControl - - - - - ---- The UNIT class --- @type UNIT --- @extends Wrapper.Controllable#CONTROLLABLE -UNIT = { - ClassName="UNIT", -} - - ---- Unit.SensorType --- @type Unit.SensorType --- @field OPTIC --- @field RADAR --- @field IRST --- @field RWR - - --- Registration. - ---- Create a new UNIT from DCSUnit. --- @param #UNIT self --- @param #string UnitName The name of the DCS unit. --- @return #UNIT -function UNIT:Register( UnitName ) - local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) - self.UnitName = UnitName - return self -end - --- Reference methods. - ---- Finds a UNIT from the _DATABASE using a DCSUnit object. --- @param #UNIT self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit An existing DCS Unit object reference. --- @return #UNIT self -function UNIT:Find( DCSUnit ) - - local UnitName = DCSUnit:getName() - local UnitFound = _DATABASE:FindUnit( UnitName ) - return UnitFound -end - ---- Find a UNIT in the _DATABASE using the name of an existing DCS Unit. --- @param #UNIT self --- @param #string UnitName The Unit Name. --- @return #UNIT self -function UNIT:FindByName( UnitName ) - - local UnitFound = _DATABASE:FindUnit( UnitName ) - return UnitFound -end - ---- Return the name of the UNIT. --- @param #UNIT self --- @return #string The UNIT name. -function UNIT:Name() - - return self.UnitName -end - - ---- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit -function UNIT:GetDCSObject() - - local DCSUnit = Unit.getByName( self.UnitName ) - - if DCSUnit then - return DCSUnit - end - - return nil -end - ---- Respawn the @{Unit} using a (tweaked) template of the parent Group. --- --- This function will: --- --- * Get the current position and heading of the group. --- * When the unit is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. --- * Then it will respawn the re-modelled group. --- --- @param #UNIT self --- @param Dcs.DCSTypes#Vec3 SpawnVec3 The position where to Spawn the new Unit at. --- @param #number Heading The heading of the unit respawn. -function UNIT:ReSpawn( SpawnVec3, Heading ) - - local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) - self:T( SpawnGroupTemplate ) - - local SpawnGroup = self:GetGroup() - - if SpawnGroup then - - local Vec3 = SpawnGroup:GetVec3() - SpawnGroupTemplate.x = SpawnVec3.x - SpawnGroupTemplate.y = SpawnVec3.z - - self:E( #SpawnGroupTemplate.units ) - for UnitID, UnitData in pairs( SpawnGroup:GetUnits() ) do - local GroupUnit = UnitData -- #UNIT - self:E( GroupUnit:GetName() ) - if GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - SpawnGroupTemplate.units[UnitID].alt = GroupUnitVec3.y - SpawnGroupTemplate.units[UnitID].x = GroupUnitVec3.x - SpawnGroupTemplate.units[UnitID].y = GroupUnitVec3.z - SpawnGroupTemplate.units[UnitID].heading = GroupUnitHeading - self:E( { UnitID, SpawnGroupTemplate.units[UnitID], SpawnGroupTemplate.units[UnitID] } ) - end - end - end - - for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do - self:T( UnitTemplateData.name ) - if UnitTemplateData.name == self:Name() then - self:T("Adjusting") - SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y - SpawnGroupTemplate.units[UnitTemplateID].x = SpawnVec3.x - SpawnGroupTemplate.units[UnitTemplateID].y = SpawnVec3.z - SpawnGroupTemplate.units[UnitTemplateID].heading = Heading - self:E( { UnitTemplateID, SpawnGroupTemplate.units[UnitTemplateID], SpawnGroupTemplate.units[UnitTemplateID] } ) - else - self:E( SpawnGroupTemplate.units[UnitTemplateID].name ) - local GroupUnit = UNIT:FindByName( SpawnGroupTemplate.units[UnitTemplateID].name ) -- #UNIT - if GroupUnit and GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - UnitTemplateData.alt = GroupUnitVec3.y - UnitTemplateData.x = GroupUnitVec3.x - UnitTemplateData.y = GroupUnitVec3.z - UnitTemplateData.heading = GroupUnitHeading - else - if SpawnGroupTemplate.units[UnitTemplateID].name ~= self:Name() then - self:T("nilling") - SpawnGroupTemplate.units[UnitTemplateID].delete = true - end - end - end - end - - -- Remove obscolete units from the group structure - i = 1 - while i <= #SpawnGroupTemplate.units do - - local UnitTemplateData = SpawnGroupTemplate.units[i] - self:T( UnitTemplateData.name ) - - if UnitTemplateData.delete then - table.remove( SpawnGroupTemplate.units, i ) - else - i = i + 1 - end - end - - _DATABASE:Spawn( SpawnGroupTemplate ) -end - - - ---- Returns if the unit is activated. --- @param #UNIT self --- @return #boolean true if Unit is activated. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsActive() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - - local UnitIsActive = DCSUnit:isActive() - return UnitIsActive - end - - return nil -end - - - ---- Returns the Unit's callsign - the localized string. --- @param #UNIT self --- @return #string The Callsign of the Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCallsign() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitCallSign = DCSUnit:getCallsign() - return UnitCallSign - end - - self:E( self.ClassName .. " " .. self.UnitName .. " not found!" ) - return nil -end - - ---- Returns name of the player that control the unit or nil if the unit is controlled by A.I. --- @param #UNIT self --- @return #string Player Name --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPlayerName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - - local PlayerName = DCSUnit:getPlayerName() - if PlayerName == nil then - PlayerName = "" - end - return PlayerName - end - - return nil -end - ---- Returns the unit's number in the group. --- The number is the same number the unit has in ME. --- It may not be changed during the mission. --- If any unit in the group is destroyed, the numbers of another units will not be changed. --- @param #UNIT self --- @return #number The Unit number. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetNumber() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitNumber = DCSUnit:getNumber() - return UnitNumber - end - - return nil -end - ---- Returns the unit's group if it exist and nil otherwise. --- @param Wrapper.Unit#UNIT self --- @return Wrapper.Group#GROUP The Group of the Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetGroup() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) - return UnitGroup - end - - return nil -end - - --- Need to add here functions to check if radar is on and which object etc. - ---- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign. --- DCS Units spawned with the @{SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name. --- The spawn sequence number and unit number are contained within the name after the '#' sign. --- @param #UNIT self --- @return #string The name of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPrefix() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix - end - - return nil -end - ---- Returns the Unit's ammunition. --- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Ammo --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetAmmo() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitAmmo = DCSUnit:getAmmo() - return UnitAmmo - end - - return nil -end - ---- Returns the unit sensors. --- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Sensors --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetSensors() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitSensors = DCSUnit:getSensors() - return UnitSensors - end - - return nil -end - --- Need to add here a function per sensortype --- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS) - ---- Returns if the unit has sensors of a certain type. --- @param #UNIT self --- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:HasSensors( ... ) - self:F2( arg ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local HasSensors = DCSUnit:hasSensors( unpack( arg ) ) - return HasSensors - end - - return nil -end - ---- Returns if the unit is SEADable. --- @param #UNIT self --- @return #boolean returns true if the unit is SEADable. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:HasSEAD() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitSEADAttributes = DCSUnit:getDesc().attributes - - local HasSEAD = false - if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or - UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true then - HasSEAD = true - end - return HasSEAD - end - - return nil -end - ---- Returns two values: --- --- * First value indicates if at least one of the unit's radar(s) is on. --- * Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @param #UNIT self --- @return #boolean Indicates if at least one of the unit's radar(s) is on. --- @return Dcs.DCSWrapper.Object#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetRadar() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() - return UnitRadarOn, UnitRadarObject - end - - return nil, nil -end - ---- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0. --- @param #UNIT self --- @return #number The relative amount of fuel (from 0.0 to 1.0). --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetFuel() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitFuel = DCSUnit:getFuel() - return UnitFuel - end - - return nil -end - ---- Returns the unit's health. Dead units has health <= 1.0. --- @param #UNIT self --- @return #number The Unit's health value. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetLife() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitLife = DCSUnit:getLife() - return UnitLife - end - - return nil -end - ---- Returns the Unit's initial health. --- @param #UNIT self --- @return #number The Unit's initial health value. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetLife0() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitLife0 = DCSUnit:getLife0() - return UnitLife0 - end - - return nil -end - ---- Returns the Unit's A2G threat level on a scale from 1 to 10 ... --- The following threat levels are foreseen: --- --- * Threat level 0: Unit is unarmed. --- * Threat level 1: Unit is infantry. --- * Threat level 2: Unit is an infantry vehicle. --- * Threat level 3: Unit is ground artillery. --- * Threat level 4: Unit is a tank. --- * Threat level 5: Unit is a modern tank or ifv with ATGM. --- * Threat level 6: Unit is a AAA. --- * Threat level 7: Unit is a SAM or manpad, IR guided. --- * Threat level 8: Unit is a Short Range SAM, radar guided. --- * Threat level 9: Unit is a Medium Range SAM, radar guided. --- * Threat level 10: Unit is a Long Range SAM, radar guided. -function UNIT:GetThreatLevel() - - local Attributes = self:GetDesc().attributes - local ThreatLevel = 0 - - local ThreatLevels = { - "Unarmed", - "Infantry", - "Old Tanks & APCs", - "Tanks & IFVs without ATGM", - "Tanks & IFV with ATGM", - "Modern Tanks", - "AAA", - "IR Guided SAMs", - "SR SAMs", - "MR SAMs", - "LR SAMs" - } - - self:T2( Attributes ) - - if Attributes["LR SAM"] then ThreatLevel = 10 - elseif Attributes["MR SAM"] then ThreatLevel = 9 - elseif Attributes["SR SAM"] and - not Attributes["IR Guided SAM"] then ThreatLevel = 8 - elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and - Attributes["IR Guided SAM"] then ThreatLevel = 7 - elseif Attributes["AAA"] then ThreatLevel = 6 - elseif Attributes["Modern Tanks"] then ThreatLevel = 5 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - Attributes["ATGM"] then ThreatLevel = 4 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - not Attributes["ATGM"] then ThreatLevel = 3 - elseif Attributes["Old Tanks"] or Attributes["APC"] then ThreatLevel = 2 - elseif Attributes["Infantry"] then ThreatLevel = 1 - end - - self:T2( ThreatLevel ) - return ThreatLevel, ThreatLevels[ThreatLevel+1] - -end - - --- Is functions - ---- Returns true if the unit is within a @{Zone}. --- @param #UNIT self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE} -function UNIT:IsInZone( Zone ) - self:F2( { self.UnitName, Zone } ) - - if self:IsAlive() then - local IsInZone = Zone:IsPointVec3InZone( self:GetVec3() ) - - self:T( { IsInZone } ) - return IsInZone - end - - return false -end - ---- Returns true if the unit is not within a @{Zone}. --- @param #UNIT self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE} -function UNIT:IsNotInZone( Zone ) - self:F2( { self.UnitName, Zone } ) - - if self:IsAlive() then - local IsInZone = not Zone:IsPointVec3InZone( self:GetVec3() ) - - self:T( { IsInZone } ) - return IsInZone - else - return false - end -end - - ---- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. --- @param #UNIT self --- @param #UNIT AwaitUnit The other UNIT wrapper object. --- @param Radius The radius in meters with the DCS Unit in the centre. --- @return true If the other DCS Unit is within the radius of the 2D point of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) - self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitVec3 = self:GetVec3() - local AwaitUnitVec3 = AwaitUnit:GetVec3() - - if (((UnitVec3.x - AwaitUnitVec3.x)^2 + (UnitVec3.z - AwaitUnitVec3.z)^2)^0.5 <= Radius) then - self:T3( "true" ) - return true - else - self:T3( "false" ) - return false - end - end - - return nil -end - - - ---- Signal a flare at the position of the UNIT. --- @param #UNIT self --- @param Utilities.Utils#FLARECOLOR FlareColor -function UNIT:Flare( FlareColor ) - self:F2() - trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 ) -end - ---- Signal a white flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareWhite() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 ) -end - ---- Signal a yellow flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareYellow() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 ) -end - ---- Signal a green flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareGreen() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 ) -end - ---- Signal a red flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareRed() - self:F2() - local Vec3 = self:GetVec3() - if Vec3 then - trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 ) - end -end - ---- Smoke the UNIT. --- @param #UNIT self -function UNIT:Smoke( SmokeColor, Range ) - self:F2() - if Range then - trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor ) - else - trigger.action.smoke( self:GetVec3(), SmokeColor ) - end - -end - ---- Smoke the UNIT Green. --- @param #UNIT self -function UNIT:SmokeGreen() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green ) -end - ---- Smoke the UNIT Red. --- @param #UNIT self -function UNIT:SmokeRed() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red ) -end - ---- Smoke the UNIT White. --- @param #UNIT self -function UNIT:SmokeWhite() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White ) -end - ---- Smoke the UNIT Orange. --- @param #UNIT self -function UNIT:SmokeOrange() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange ) -end - ---- Smoke the UNIT Blue. --- @param #UNIT self -function UNIT:SmokeBlue() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue ) -end - --- Is methods - ---- Returns if the unit is of an air category. --- If the unit is a helicopter or a plane, then this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Air category evaluation result. -function UNIT:IsAir() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) - - local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) - - self:T3( IsAirResult ) - return IsAirResult - end - - return nil -end - ---- Returns if the unit is of an ground category. --- If the unit is a ground vehicle or infantry, this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Ground category evaluation result. -function UNIT:IsGround() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) - - local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) - - self:T3( IsGroundResult ) - return IsGroundResult - end - - return nil -end - ---- Returns if the unit is a friendly unit. --- @param #UNIT self --- @return #boolean IsFriendly evaluation result. -function UNIT:IsFriendly( FriendlyCoalition ) - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitCoalition = DCSUnit:getCoalition() - self:T3( { UnitCoalition, FriendlyCoalition } ) - - local IsFriendlyResult = ( UnitCoalition == FriendlyCoalition ) - - self:E( IsFriendlyResult ) - return IsFriendlyResult - end - - return nil -end - ---- Returns if the unit is of a ship category. --- If the unit is a ship, this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Ship category evaluation result. -function UNIT:IsShip() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.SHIP } ) - - local IsShipResult = ( UnitDescriptor.category == Unit.Category.SHIP ) - - self:T3( IsShipResult ) - return IsShipResult - end - - return nil -end - ---- This module contains the CLIENT class. --- --- 1) @{Wrapper.Client#CLIENT} class, extends @{Wrapper.Unit#UNIT} --- =============================================== --- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. --- Note that clients are NOT the same as Units, they are NOT necessarily alive. --- The @{Wrapper.Client#CLIENT} class is a wrapper class to handle the DCS Unit objects that have the skillset defined as __Client__ or __Player__: --- --- * Wraps the DCS Unit objects with skill level set to Player or Client. --- * Support all DCS Unit APIs. --- * Enhance with Unit specific APIs not in the DCS Group API set. --- * When player joins Unit, execute alive init logic. --- * Handles messages to players. --- * Manage the "state" of the DCS Unit. --- --- Clients are being used by the @{MISSION} class to follow players and register their successes. --- --- 1.1) CLIENT reference methods --- ----------------------------- --- For each DCS Unit having skill level Player or Client, a CLIENT wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The CLIENT class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the DCS Unit or the DCS UnitName. --- --- Another thing to know is that CLIENT objects do not "contain" the DCS Unit object. --- The CLIENT methods will reference the DCS Unit object by name when it is needed during API execution. --- If the DCS Unit object does not exist or is nil, the CLIENT methods will return nil and log an exception in the DCS.log file. --- --- The CLIENT class provides the following functions to retrieve quickly the relevant CLIENT instance: --- --- * @{#CLIENT.Find}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit object. --- * @{#CLIENT.FindByName}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these CLIENT OBJECT REFERENCES! (make the CLIENT object references nil). --- --- @module Client --- @author FlightControl - ---- The CLIENT class --- @type CLIENT --- @extends Wrapper.Unit#UNIT -CLIENT = { - ONBOARDSIDE = { - NONE = 0, - LEFT = 1, - RIGHT = 2, - BACK = 3, - FRONT = 4 - }, - ClassName = "CLIENT", - ClientName = nil, - ClientAlive = false, - ClientTransport = false, - ClientBriefingShown = false, - _Menus = {}, - _Tasks = {}, - Messages = { - } -} - - ---- Finds a CLIENT from the _DATABASE using the relevant DCS Unit. --- @param #CLIENT self --- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. --- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @return #CLIENT --- @usage --- -- Create new Clients. --- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) --- Mission:AddGoal( DeploySA6TroopsGoal ) --- --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) -function CLIENT:Find( DCSUnit ) - local ClientName = DCSUnit:getName() - local ClientFound = _DATABASE:FindClient( ClientName ) - - if ClientFound then - ClientFound:F( ClientName ) - return ClientFound - end - - error( "CLIENT not found for: " .. ClientName ) -end - - ---- Finds a CLIENT from the _DATABASE using the relevant Client Unit Name. --- As an optional parameter, a briefing text can be given also. --- @param #CLIENT self --- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. --- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @param #boolean Error A flag that indicates whether an error should be raised if the CLIENT cannot be found. By default an error will be raised. --- @return #CLIENT --- @usage --- -- Create new Clients. --- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) --- Mission:AddGoal( DeploySA6TroopsGoal ) --- --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) -function CLIENT:FindByName( ClientName, ClientBriefing, Error ) - local ClientFound = _DATABASE:FindClient( ClientName ) - - if ClientFound then - ClientFound:F( { ClientName, ClientBriefing } ) - ClientFound:AddBriefing( ClientBriefing ) - ClientFound.MessageSwitch = true - - return ClientFound - end - - if not Error then - error( "CLIENT not found for: " .. ClientName ) - end -end - -function CLIENT:Register( ClientName ) - local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) - - self:F( ClientName ) - self.ClientName = ClientName - self.MessageSwitch = true - self.ClientAlive2 = false - - --self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 ) - self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5 ) - - self:E( self ) - return self -end - - ---- Transport defines that the Client is a Transport. Transports show cargo. --- @param #CLIENT self --- @return #CLIENT -function CLIENT:Transport() - self:F() - - self.ClientTransport = true - return self -end - ---- AddBriefing adds a briefing to a CLIENT when a player joins a mission. --- @param #CLIENT self --- @param #string ClientBriefing is the text defining the Mission briefing. --- @return #CLIENT self -function CLIENT:AddBriefing( ClientBriefing ) - self:F( ClientBriefing ) - self.ClientBriefing = ClientBriefing - self.ClientBriefingShown = false - - return self -end - ---- Show the briefing of a CLIENT. --- @param #CLIENT self --- @return #CLIENT self -function CLIENT:ShowBriefing() - self:F( { self.ClientName, self.ClientBriefingShown } ) - - if not self.ClientBriefingShown then - self.ClientBriefingShown = true - local Briefing = "" - if self.ClientBriefing then - Briefing = Briefing .. self.ClientBriefing - end - Briefing = Briefing .. " Press [LEFT ALT]+[B] to view the complete mission briefing." - self:Message( Briefing, 60, "Briefing" ) - end - - return self -end - ---- Show the mission briefing of a MISSION to the CLIENT. --- @param #CLIENT self --- @param #string MissionBriefing --- @return #CLIENT self -function CLIENT:ShowMissionBriefing( MissionBriefing ) - self:F( { self.ClientName } ) - - if MissionBriefing then - self:Message( MissionBriefing, 60, "Mission Briefing" ) - end - - return self -end - - - ---- Resets a CLIENT. --- @param #CLIENT self --- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. -function CLIENT:Reset( ClientName ) - self:F() - self._Menus = {} -end - --- Is Functions - ---- Checks if the CLIENT is a multi-seated UNIT. --- @param #CLIENT self --- @return #boolean true if multi-seated. -function CLIENT:IsMultiSeated() - self:F( self.ClientName ) - - local ClientMultiSeatedTypes = { - ["Mi-8MT"] = "Mi-8MT", - ["UH-1H"] = "UH-1H", - ["P-51B"] = "P-51B" - } - - if self:IsAlive() then - local ClientTypeName = self:GetClientGroupUnit():GetTypeName() - if ClientMultiSeatedTypes[ClientTypeName] then - return true - end - end - - return false -end - ---- Checks for a client alive event and calls a function on a continuous basis. --- @param #CLIENT self --- @param #function CallBack Function. --- @return #CLIENT -function CLIENT:Alive( CallBackFunction, ... ) - self:F() - - self.ClientCallBack = CallBackFunction - self.ClientParameters = arg - - return self -end - ---- @param #CLIENT self -function CLIENT:_AliveCheckScheduler( SchedulerName ) - self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } ) - - if self:IsAlive() then - if self.ClientAlive2 == false then - self:ShowBriefing() - if self.ClientCallBack then - self:T("Calling Callback function") - self.ClientCallBack( self, unpack( self.ClientParameters ) ) - end - self.ClientAlive2 = true - end - else - if self.ClientAlive2 == true then - self.ClientAlive2 = false - end - end - - return true -end - ---- Return the DCSGroup of a Client. --- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @param #CLIENT self --- @return Dcs.DCSWrapper.Group#Group -function CLIENT:GetDCSGroup() - self:F3() - --- local ClientData = Group.getByName( self.ClientName ) --- if ClientData and ClientData:isExist() then --- self:T( self.ClientName .. " : group found!" ) --- return ClientData --- else --- return nil --- end - - local ClientUnit = Unit.getByName( self.ClientName ) - - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - self:T3( { "CoalitionData:", CoalitionData } ) - for UnitId, UnitData in pairs( CoalitionData ) do - self:T3( { "UnitData:", UnitData } ) - if UnitData and UnitData:isExist() then - - --self:E(self.ClientName) - if ClientUnit then - local ClientGroup = ClientUnit:getGroup() - if ClientGroup then - self:T3( "ClientGroup = " .. self.ClientName ) - if ClientGroup:isExist() and UnitData:getGroup():isExist() then - if ClientGroup:getID() == UnitData:getGroup():getID() then - self:T3( "Normal logic" ) - self:T3( self.ClientName .. " : group found!" ) - self.ClientGroupID = ClientGroup:getID() - self.ClientGroupName = ClientGroup:getName() - return ClientGroup - end - else - -- Now we need to resolve the bugs in DCS 1.5 ... - -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) - self:T3( "Bug 1.5 logic" ) - local ClientGroupTemplate = _DATABASE.Templates.Units[self.ClientName].GroupTemplate - self.ClientGroupID = ClientGroupTemplate.groupId - self.ClientGroupName = _DATABASE.Templates.Units[self.ClientName].GroupName - self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) - return ClientGroup - end - -- else - -- error( "Client " .. self.ClientName .. " not found!" ) - end - else - --self:E( { "Client not found!", self.ClientName } ) - end - end - end - end - - -- For non player clients - if ClientUnit then - local ClientGroup = ClientUnit:getGroup() - if ClientGroup then - self:T3( "ClientGroup = " .. self.ClientName ) - if ClientGroup:isExist() then - self:T3( "Normal logic" ) - self:T3( self.ClientName .. " : group found!" ) - return ClientGroup - end - end - end - - self.ClientGroupID = nil - self.ClientGroupUnit = nil - - return nil -end - - --- TODO: Check Dcs.DCSTypes#Group.ID ---- Get the group ID of the client. --- @param #CLIENT self --- @return Dcs.DCSTypes#Group.ID -function CLIENT:GetClientGroupID() - - local ClientGroup = self:GetDCSGroup() - - --self:E( self.ClientGroupID ) -- Determined in GetDCSGroup() - return self.ClientGroupID -end - - ---- Get the name of the group of the client. --- @param #CLIENT self --- @return #string -function CLIENT:GetClientGroupName() - - local ClientGroup = self:GetDCSGroup() - - self:T( self.ClientGroupName ) -- Determined in GetDCSGroup() - return self.ClientGroupName -end - ---- Returns the UNIT of the CLIENT. --- @param #CLIENT self --- @return Wrapper.Unit#UNIT -function CLIENT:GetClientGroupUnit() - self:F2() - - local ClientDCSUnit = Unit.getByName( self.ClientName ) - - self:T( self.ClientDCSUnit ) - if ClientDCSUnit and ClientDCSUnit:isExist() then - local ClientUnit = _DATABASE:FindUnit( self.ClientName ) - self:T2( ClientUnit ) - return ClientUnit - end -end - ---- Returns the DCSUnit of the CLIENT. --- @param #CLIENT self --- @return Dcs.DCSTypes#Unit -function CLIENT:GetClientGroupDCSUnit() - self:F2() - - local ClientDCSUnit = Unit.getByName( self.ClientName ) - - if ClientDCSUnit and ClientDCSUnit:isExist() then - self:T2( ClientDCSUnit ) - return ClientDCSUnit - end -end - - ---- Evaluates if the CLIENT is a transport. --- @param #CLIENT self --- @return #boolean true is a transport. -function CLIENT:IsTransport() - self:F() - return self.ClientTransport -end - ---- Shows the @{AI.AI_Cargo#CARGO} contained within the CLIENT to the player as a message. --- The @{AI.AI_Cargo#CARGO} is shown using the @{Core.Message#MESSAGE} distribution system. --- @param #CLIENT self -function CLIENT:ShowCargo() - self:F() - - local CargoMsg = "" - - for CargoName, Cargo in pairs( CARGOS ) do - if self == Cargo:IsLoadedInClient() then - CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n" - end - end - - if CargoMsg == "" then - CargoMsg = "empty" - end - - self:Message( CargoMsg, 15, "Co-Pilot: Cargo Status", 30 ) - -end - --- TODO (1) I urgently need to revise this. ---- A local function called by the DCS World Menu system to switch off messages. -function CLIENT.SwitchMessages( PrmTable ) - PrmTable[1].MessageSwitch = PrmTable[2] -end - ---- The main message driver for the CLIENT. --- This function displays various messages to the Player logged into the CLIENT through the DCS World Messaging system. --- @param #CLIENT self --- @param #string Message is the text describing the message. --- @param #number MessageDuration is the duration in seconds that the Message should be displayed. --- @param #string MessageCategory is the category of the message (the title). --- @param #number MessageInterval is the interval in seconds between the display of the @{Core.Message#MESSAGE} when the CLIENT is in the air. --- @param #string MessageID is the identifier of the message when displayed with intervals. -function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInterval, MessageID ) - self:F( { Message, MessageDuration, MessageCategory, MessageInterval } ) - - if self.MessageSwitch == true then - if MessageCategory == nil then - MessageCategory = "Messages" - end - if MessageID ~= nil then - if self.Messages[MessageID] == nil then - self.Messages[MessageID] = {} - self.Messages[MessageID].MessageId = MessageID - self.Messages[MessageID].MessageTime = timer.getTime() - self.Messages[MessageID].MessageDuration = MessageDuration - if MessageInterval == nil then - self.Messages[MessageID].MessageInterval = 600 - else - self.Messages[MessageID].MessageInterval = MessageInterval - end - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - else - if self:GetClientGroupDCSUnit() and not self:GetClientGroupDCSUnit():inAir() then - if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + 10 then - MESSAGE:New( Message, MessageDuration , MessageCategory):ToClient( self ) - self.Messages[MessageID].MessageTime = timer.getTime() - end - else - if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + self.Messages[MessageID].MessageInterval then - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - self.Messages[MessageID].MessageTime = timer.getTime() - end - end - end - else - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - end - end -end ---- This module contains the STATIC class. --- --- 1) @{Wrapper.Static#STATIC} class, extends @{Wrapper.Positionable#POSITIONABLE} --- =============================================================== --- Statics are **Static Units** defined within the Mission Editor. --- Note that Statics are almost the same as Units, but they don't have a controller. --- The @{Wrapper.Static#STATIC} class is a wrapper class to handle the DCS Static objects: --- --- * Wraps the DCS Static objects. --- * Support all DCS Static APIs. --- * Enhance with Static specific APIs not in the DCS API set. --- --- 1.1) STATIC reference methods --- ----------------------------- --- For each DCS Static will have a STATIC wrapper object (instance) within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The STATIC class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the Static Name. --- --- Another thing to know is that STATIC objects do not "contain" the DCS Static object. --- The STATIc methods will reference the DCS Static object by name when it is needed during API execution. --- If the DCS Static object does not exist or is nil, the STATIC methods will return nil and log an exception in the DCS.log file. --- --- The STATIc class provides the following functions to retrieve quickly the relevant STATIC instance: --- --- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil). --- --- @module Static --- @author FlightControl - - - - - - ---- The STATIC class --- @type STATIC --- @extends Wrapper.Positionable#POSITIONABLE -STATIC = { - ClassName = "STATIC", -} - - ---- Finds a STATIC from the _DATABASE using the relevant Static Name. --- As an optional parameter, a briefing text can be given also. --- @param #STATIC self --- @param #string StaticName Name of the DCS **Static** as defined within the Mission Editor. --- @return #STATIC -function STATIC:FindByName( StaticName ) - local StaticFound = _DATABASE:FindStatic( StaticName ) - - self.StaticName = StaticName - - if StaticFound then - StaticFound:F( { StaticName } ) - - return StaticFound - end - - error( "STATIC not found for: " .. StaticName ) -end - -function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) - self.StaticName = StaticName - return self -end - - -function STATIC:GetDCSObject() - local DCSStatic = StaticObject.getByName( self.StaticName ) - - if DCSStatic then - return DCSStatic - end - - return nil -end ---- This module contains the AIRBASE classes. --- --- === --- --- 1) @{Wrapper.Airbase#AIRBASE} class, extends @{Wrapper.Positionable#POSITIONABLE} --- ================================================================= --- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: --- --- * Support all DCS Airbase APIs. --- * Enhance with Airbase specific APIs not in the DCS Airbase API set. --- --- --- 1.1) AIRBASE reference methods --- ------------------------------ --- For each DCS Airbase object alive within a running mission, a AIRBASE wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The AIRBASE class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference --- using the DCS Airbase or the DCS AirbaseName. --- --- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object. --- The AIRBASE methods will reference the DCS Airbase object by name when it is needed during API execution. --- If the DCS Airbase object does not exist or is nil, the AIRBASE methods will return nil and log an exception in the DCS.log file. --- --- The AIRBASE class provides the following functions to retrieve quickly the relevant AIRBASE instance: --- --- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object. --- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil). --- --- 1.2) DCS AIRBASE APIs --- --------------------- --- The DCS Airbase APIs are used extensively within MOOSE. The AIRBASE class has for each DCS Airbase API a corresponding method. --- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call, --- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{Dcs.DCSWrapper.Airbase#Airbase.getName}() --- is implemented in the AIRBASE class as @{#AIRBASE.GetName}(). --- --- More functions will be added --- ---------------------------- --- During the MOOSE development, more functions will be added. --- --- @module Airbase --- @author FlightControl - - - - - ---- The AIRBASE class --- @type AIRBASE --- @extends Wrapper.Positionable#POSITIONABLE -AIRBASE = { - ClassName="AIRBASE", - CategoryName = { - [Airbase.Category.AIRDROME] = "Airdrome", - [Airbase.Category.HELIPAD] = "Helipad", - [Airbase.Category.SHIP] = "Ship", - }, - } - --- Registration. - ---- Create a new AIRBASE from DCSAirbase. --- @param #AIRBASE self --- @param #string AirbaseName The name of the airbase. --- @return Wrapper.Airbase#AIRBASE -function AIRBASE:Register( AirbaseName ) - - local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) - self.AirbaseName = AirbaseName - return self -end - --- Reference methods. - ---- Finds a AIRBASE from the _DATABASE using a DCSAirbase object. --- @param #AIRBASE self --- @param Dcs.DCSWrapper.Airbase#Airbase DCSAirbase An existing DCS Airbase object reference. --- @return Wrapper.Airbase#AIRBASE self -function AIRBASE:Find( DCSAirbase ) - - local AirbaseName = DCSAirbase:getName() - local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) - return AirbaseFound -end - ---- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase. --- @param #AIRBASE self --- @param #string AirbaseName The Airbase Name. --- @return Wrapper.Airbase#AIRBASE self -function AIRBASE:FindByName( AirbaseName ) - - local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) - return AirbaseFound -end - -function AIRBASE:GetDCSObject() - local DCSAirbase = Airbase.getByName( self.AirbaseName ) - - if DCSAirbase then - return DCSAirbase - end - - return nil -end - - - ---- Scoring system for MOOSE. --- This scoring class calculates the hits and kills that players make within a simulation session. --- Scoring is calculated using a defined algorithm. --- With a small change in MissionScripting.lua, the scoring can also be logged in a CSV file, that can then be uploaded --- to a database or a BI tool to publish the scoring results to the player community. --- @module Scoring --- @author FlightControl - - ---- The Scoring class --- @type SCORING --- @field Players A collection of the current players that have joined the game. --- @extends Core.Base#BASE -SCORING = { - ClassName = "SCORING", - ClassID = 0, - Players = {}, -} - -local _SCORINGCoalition = - { - [1] = "Red", - [2] = "Blue", - } - -local _SCORINGCategory = - { - [Unit.Category.AIRPLANE] = "Plane", - [Unit.Category.HELICOPTER] = "Helicopter", - [Unit.Category.GROUND_UNIT] = "Vehicle", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - } - ---- Creates a new SCORING object to administer the scoring achieved by players. --- @param #SCORING self --- @param #string GameName The name of the game. This name is also logged in the CSV score file. --- @return #SCORING self --- @usage --- -- Define a new scoring object for the mission Gori Valley. --- ScoringObject = SCORING:New( "Gori Valley" ) -function SCORING:New( GameName ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - if GameName then - self.GameName = GameName - else - error( "A game name must be given to register the scoring results" ) - end - - - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnHit( self._EventOnHit, self ) - - --self.SchedulerId = routines.scheduleFunction( SCORING._FollowPlayersScheduled, { self }, 0, 5 ) - self.SchedulerId = SCHEDULER:New( self, self._FollowPlayersScheduled, {}, 0, 5 ) - - self:ScoreMenu() - - self:OpenCSV( GameName) - - return self - -end - ---- Creates a score radio menu. Can be accessed using Radio -> F10. --- @param #SCORING self --- @return #SCORING self -function SCORING:ScoreMenu() - self.Menu = MENU_MISSION:New( 'Scoring' ) - self.AllScoresMenu = MENU_MISSION_COMMAND:New( 'Score All Active Players', self.Menu, SCORING.ReportScoreAll, self ) - --- = COMMANDMENU:New('Your Current Score', ReportScore, SCORING.ReportScorePlayer, self ) - return self -end - ---- Follows new players entering Clients within the DCSRTE. --- TODO: Need to see if i can catch this also with an event. It will eliminate the schedule ... -function SCORING:_FollowPlayersScheduled() - self:F3( "_FollowPlayersScheduled" ) - - local ClientUnit = 0 - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } - local unitId - local unitData - local AlivePlayerUnits = {} - - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - self:T3( { "_FollowPlayersScheduled", CoalitionData } ) - for UnitId, UnitData in pairs( CoalitionData ) do - self:_AddPlayerFromUnit( UnitData ) - end - end - - return true -end - - ---- Track DEAD or CRASH events for the scoring. --- @param #SCORING self --- @param Core.Event#EVENTDATA Event -function SCORING:_EventOnDeadOrCrash( Event ) - self:F( { Event } ) - - local TargetUnit = nil - local TargetGroup = nil - local TargetUnitName = "" - local TargetGroupName = "" - local TargetPlayerName = "" - local TargetCoalition = nil - local TargetCategory = nil - local TargetType = nil - local TargetUnitCoalition = nil - local TargetUnitCategory = nil - local TargetUnitType = nil - - if Event.IniDCSUnit then - - TargetUnit = Event.IniDCSUnit - TargetUnitName = Event.IniDCSUnitName - TargetGroup = Event.IniDCSGroup - TargetGroupName = Event.IniDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() - - TargetCoalition = TargetUnit:getCoalition() - --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category -- Workaround - TargetType = TargetUnit:getTypeName() - - TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] - TargetUnitCategory = _SCORINGCategory[TargetCategory] - TargetUnitType = TargetType - - self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) - end - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Something got killed" ) - - -- Some variables - local InitUnitName = PlayerData.UnitName - local InitUnitType = PlayerData.UnitType - local InitCoalition = PlayerData.UnitCoalition - local InitCategory = PlayerData.UnitCategory - local InitUnitCoalition = _SCORINGCoalition[InitCoalition] - local InitUnitCategory = _SCORINGCategory[InitCategory] - - self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) - - -- What is he hitting? - if TargetCategory then - if PlayerData and PlayerData.Hit and PlayerData.Hit[TargetCategory] and PlayerData.Hit[TargetCategory][TargetUnitName] then -- Was there a hit for this unit for this player before registered??? - if not PlayerData.Kill[TargetCategory] then - PlayerData.Kill[TargetCategory] = {} - end - if not PlayerData.Kill[TargetCategory][TargetType] then - PlayerData.Kill[TargetCategory][TargetType] = {} - PlayerData.Kill[TargetCategory][TargetType].Score = 0 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = 0 - PlayerData.Kill[TargetCategory][TargetType].Penalty = 0 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0 - end - - if InitCoalition == TargetCoalition then - PlayerData.Penalty = PlayerData.Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].Penalty = PlayerData.Kill[TargetCategory][TargetType].Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Penalty: -" .. PlayerData.Kill[TargetCategory][TargetType].Penalty .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - PlayerData.Score = PlayerData.Score + 10 - PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = PlayerData.Kill[TargetCategory][TargetType].ScoreKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed an enemy " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].ScoreKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Score .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_SCORE", 1, 10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end - end - end - end -end - - - ---- Add a new player entering a Unit. -function SCORING:_AddPlayerFromUnit( UnitData ) - self:F( UnitData ) - - if UnitData and UnitData:isExist() then - local UnitName = UnitData:getName() - local PlayerName = UnitData:getPlayerName() - local UnitDesc = UnitData:getDesc() - local UnitCategory = UnitDesc.category - local UnitCoalition = UnitData:getCoalition() - local UnitTypeName = UnitData:getTypeName() - - self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } ) - - if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ... - self.Players[PlayerName] = {} - self.Players[PlayerName].Hit = {} - self.Players[PlayerName].Kill = {} - self.Players[PlayerName].Mission = {} - - -- for CategoryID, CategoryName in pairs( SCORINGCategory ) do - -- self.Players[PlayerName].Hit[CategoryID] = {} - -- self.Players[PlayerName].Kill[CategoryID] = {} - -- end - self.Players[PlayerName].HitPlayers = {} - self.Players[PlayerName].HitUnits = {} - self.Players[PlayerName].Score = 0 - self.Players[PlayerName].Penalty = 0 - self.Players[PlayerName].PenaltyCoalition = 0 - self.Players[PlayerName].PenaltyWarning = 0 - end - - if not self.Players[PlayerName].UnitCoalition then - self.Players[PlayerName].UnitCoalition = UnitCoalition - else - if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then - self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50 - self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. - "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", - 2 - ):ToAll() - self:ScoreCSV( PlayerName, "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, - UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:getTypeName() ) - end - end - self.Players[PlayerName].UnitName = UnitName - self.Players[PlayerName].UnitCoalition = UnitCoalition - self.Players[PlayerName].UnitCategory = UnitCategory - self.Players[PlayerName].UnitType = UnitTypeName - - if self.Players[PlayerName].Penalty > 100 then - if self.Players[PlayerName].PenaltyWarning < 1 then - MESSAGE:New( "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than 150, you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, - 30 - ):ToAll() - self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 - end - end - - if self.Players[PlayerName].Penalty > 150 then - ClientGroup = GROUP:NewFromDCSUnit( UnitData ) - ClientGroup:Destroy() - MESSAGE:New( "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", - 10 - ):ToAll() - end - - end -end - - ---- Registers Scores the players completing a Mission Task. --- @param #SCORING self --- @param Tasking.Mission#MISSION Mission --- @param Wrapper.Unit#UNIT PlayerUnit --- @param #string Text --- @param #number Score -function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) - - local PlayerName = PlayerUnit:GetPlayerName() - local MissionName = Mission:GetName() - - self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } ) - - local PlayerData = self.Players[PlayerName] - - if not PlayerData.Mission[MissionName] then - PlayerData.Mission[MissionName] = {} - PlayerData.Mission[MissionName].ScoreTask = 0 - PlayerData.Mission[MissionName].ScoreMission = 0 - end - - self:T( PlayerName ) - self:T( PlayerData.Mission[MissionName] ) - - PlayerData.Score = self.Players[PlayerName].Score + Score - PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score - - MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. - Score .. " task score!", - 30 ):ToAll() - - self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) -end - - ---- Registers Mission Scores for possible multiple players that contributed in the Mission. --- @param #SCORING self --- @param Tasking.Mission#MISSION Mission --- @param Wrapper.Unit#UNIT PlayerUnit --- @param #string Text --- @param #number Score -function SCORING:_AddMissionScore( Mission, Text, Score ) - - local MissionName = Mission:GetName() - - self:E( { Mission, Text, Score } ) - self:E( self.Players ) - - for PlayerName, PlayerData in pairs( self.Players ) do - - self:E( PlayerData ) - if PlayerData.Mission[MissionName] then - - PlayerData.Score = PlayerData.Score + Score - PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score - - MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. - Score .. " mission score!", - 60 ):ToAll() - - self:ScoreCSV( PlayerName, "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score ) - end - end -end - ---- Handles the OnHit event for the scoring. --- @param #SCORING self --- @param Core.Event#EVENTDATA Event -function SCORING:_EventOnHit( Event ) - self:F( { Event } ) - - local InitUnit = nil - local InitUnitName = "" - local InitGroup = nil - local InitGroupName = "" - local InitPlayerName = nil - - local InitCoalition = nil - local InitCategory = nil - local InitType = nil - local InitUnitCoalition = nil - local InitUnitCategory = nil - local InitUnitType = nil - - local TargetUnit = nil - local TargetUnitName = "" - local TargetGroup = nil - local TargetGroupName = "" - local TargetPlayerName = "" - - local TargetCoalition = nil - local TargetCategory = nil - local TargetType = nil - local TargetUnitCoalition = nil - local TargetUnitCategory = nil - local TargetUnitType = nil - - if Event.IniDCSUnit then - - InitUnit = Event.IniDCSUnit - InitUnitName = Event.IniDCSUnitName - InitGroup = Event.IniDCSGroup - InitGroupName = Event.IniDCSGroupName - InitPlayerName = InitUnit:getPlayerName() - - InitCoalition = InitUnit:getCoalition() - --TODO: Workaround Client DCS Bug - --InitCategory = InitUnit:getCategory() - InitCategory = InitUnit:getDesc().category - InitType = InitUnit:getTypeName() - - InitUnitCoalition = _SCORINGCoalition[InitCoalition] - InitUnitCategory = _SCORINGCategory[InitCategory] - InitUnitType = InitType - - self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } ) - end - - - if Event.TgtDCSUnit then - - TargetUnit = Event.TgtDCSUnit - TargetUnitName = Event.TgtDCSUnitName - TargetGroup = Event.TgtDCSGroup - TargetGroupName = Event.TgtDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() - - TargetCoalition = TargetUnit:getCoalition() - --TODO: Workaround Client DCS Bug - --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category - TargetType = TargetUnit:getTypeName() - - TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] - TargetUnitCategory = _SCORINGCategory[TargetCategory] - TargetUnitType = TargetType - - self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } ) - end - - if InitPlayerName ~= nil then -- It is a player that is hitting something - self:_AddPlayerFromUnit( InitUnit ) - if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway. - if TargetPlayerName ~= nil then -- It is a player hitting another player ... - self:_AddPlayerFromUnit( TargetUnit ) - self.Players[InitPlayerName].HitPlayers = self.Players[InitPlayerName].HitPlayers + 1 - end - - self:T( "Hitting Something" ) - -- What is he hitting? - if TargetCategory then - if not self.Players[InitPlayerName].Hit[TargetCategory] then - self.Players[InitPlayerName].Hit[TargetCategory] = {} - end - if not self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] then - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] = {} - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = 0 - end - local Score = 0 - if InitCoalition == TargetCoalition then - self.Players[InitPlayerName].Penalty = self.Players[InitPlayerName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit .. " times. Penalty: -" .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - self.Players[InitPlayerName].Score = self.Players[InitPlayerName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit .. " times. Score: " .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end - end - elseif InitPlayerName == nil then -- It is an AI hitting a player??? - - end -end - - -function SCORING:ReportScoreAll() - - env.info( "Hello World " ) - - local ScoreMessage = "" - local PlayerMessage = "" - - self:T( "Score Report" ) - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) - - -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName - - local PlayerScore = 0 - local PlayerPenalty = 0 - - ScoreMessage = ":\n" - - local ScoreMessageHits = "" - - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit - end - local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. "\n" - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( " %s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. "\n" - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. " Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties .. "\n" - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")\n" - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score:%d (%d Score -%d Penalties)%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) - end - end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() -end - - -function SCORING:ReportScorePlayer() - - env.info( "Hello World " ) - - local ScoreMessage = "" - local PlayerMessage = "" - - self:T( "Score Report" ) - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) - - -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName - - local PlayerScore = 0 - local PlayerPenalty = 0 - - ScoreMessage = "" - - local ScoreMessageHits = "" - - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit - end - local ScoreMessageHit = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreHit, PenaltyHit ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. "\n Hits: " .. ScoreMessageHits .. " " - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreKill, PenaltyKill ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. "\n Kills: " .. ScoreMessageKills .. " " - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. "\n Coalition: " .. ScoreMessageCoalitionChangePenalties .. " " - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. "\n Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") " - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties ):%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) - end - end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() - -end - - -function SCORING:SecondsToClock(sSeconds) - local nSeconds = sSeconds - if nSeconds == 0 then - --return nil; - return "00:00:00"; - else - nHours = string.format("%02.f", math.floor(nSeconds/3600)); - nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); - nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); - return nHours..":"..nMins..":"..nSecs - end -end - ---- Opens a score CSV file to log the scores. --- @param #SCORING self --- @param #string ScoringCSV --- @return #SCORING self --- @usage --- -- Open a new CSV file to log the scores of the game Gori Valley. Let the name of the CSV file begin with "Player Scores". --- ScoringObject = SCORING:New( "Gori Valley" ) --- ScoringObject:OpenCSV( "Player Scores" ) -function SCORING:OpenCSV( ScoringCSV ) - self:F( ScoringCSV ) - - if lfs and io and os then - if ScoringCSV then - self.ScoringCSV = ScoringCSV - local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" - - self.CSVFile, self.err = io.open( fdir, "w+" ) - if not self.CSVFile then - error( "Error: Cannot open CSV file in " .. lfs.writedir() ) - end - - self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' ) - - self.RunTime = os.date("%y-%m-%d_%H-%M-%S") - else - error( "A string containing the CSV file name must be given." ) - end - else - self:E( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) - end - return self -end - - ---- Registers a score for a player. --- @param #SCORING self --- @param #string PlayerName The name of the player. --- @param #string ScoreType The type of the score. --- @param #string ScoreTimes The amount of scores achieved. --- @param #string ScoreAmount The score given. --- @param #string PlayerUnitName The unit name of the player. --- @param #string PlayerUnitCoalition The coalition of the player unit. --- @param #string PlayerUnitCategory The category of the player unit. --- @param #string PlayerUnitType The type of the player unit. --- @param #string TargetUnitName The name of the target unit. --- @param #string TargetUnitCoalition The coalition of the target unit. --- @param #string TargetUnitCategory The category of the target unit. --- @param #string TargetUnitType The type of the target unit. --- @return #SCORING self -function SCORING:ScoreCSV( PlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - --write statistic information to file - local ScoreTime = self:SecondsToClock( timer.getTime() ) - PlayerName = PlayerName:gsub( '"', '_' ) - - if PlayerUnitName and PlayerUnitName ~= '' then - local PlayerUnit = Unit.getByName( PlayerUnitName ) - - if PlayerUnit then - if not PlayerUnitCategory then - --PlayerUnitCategory = SCORINGCategory[PlayerUnit:getCategory()] - PlayerUnitCategory = _SCORINGCategory[PlayerUnit:getDesc().category] - end - - if not PlayerUnitCoalition then - PlayerUnitCoalition = _SCORINGCoalition[PlayerUnit:getCoalition()] - end - - if not PlayerUnitType then - PlayerUnitType = PlayerUnit:getTypeName() - end - else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' - end - else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' - end - - if not TargetUnitCoalition then - TargetUnitCoalition = '' - end - - if not TargetUnitCategory then - TargetUnitCategory = '' - end - - if not TargetUnitType then - TargetUnitType = '' - end - - if not TargetUnitName then - TargetUnitName = '' - end - - if lfs and io and os then - self.CSVFile:write( - '"' .. self.GameName .. '"' .. ',' .. - '"' .. self.RunTime .. '"' .. ',' .. - '' .. ScoreTime .. '' .. ',' .. - '"' .. PlayerName .. '"' .. ',' .. - '"' .. ScoreType .. '"' .. ',' .. - '"' .. PlayerUnitCoalition .. '"' .. ',' .. - '"' .. PlayerUnitCategory .. '"' .. ',' .. - '"' .. PlayerUnitType .. '"' .. ',' .. - '"' .. PlayerUnitName .. '"' .. ',' .. - '"' .. TargetUnitCoalition .. '"' .. ',' .. - '"' .. TargetUnitCategory .. '"' .. ',' .. - '"' .. TargetUnitType .. '"' .. ',' .. - '"' .. TargetUnitName .. '"' .. ',' .. - '' .. ScoreTimes .. '' .. ',' .. - '' .. ScoreAmount - ) - - self.CSVFile:write( "\n" ) - end -end - - -function SCORING:CloseCSV() - if lfs and io and os then - self.CSVFile:close() - end -end - ---- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area. --- @module CleanUp --- @author Flightcontrol - - - - - - - ---- The CLEANUP class. --- @type CLEANUP --- @extends Core.Base#BASE -CLEANUP = { - ClassName = "CLEANUP", - ZoneNames = {}, - TimeInterval = 300, - CleanUpList = {}, -} - ---- Creates the main object which is handling the cleaning of the debris within the given Zone Names. --- @param #CLEANUP self --- @param #table ZoneNames Is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name. --- @param #number TimeInterval The interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes. --- @return #CLEANUP --- @usage --- -- Clean these Zones. --- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 ) --- or --- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) --- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) -function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:F( { ZoneNames, TimeInterval } ) - - if type( ZoneNames ) == 'table' then - self.ZoneNames = ZoneNames - else - self.ZoneNames = { ZoneNames } - end - if TimeInterval then - self.TimeInterval = TimeInterval - end - - _EVENTDISPATCHER:OnBirth( self._OnEventBirth, self ) - - self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) - - return self -end - - ---- Destroys a group from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSWrapper.Group#Group GroupObject The object to be destroyed. --- @param #string CleanUpGroupName The groupname... -function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) - self:F( { GroupObject, CleanUpGroupName } ) - - if GroupObject then -- and GroupObject:isExist() then - trigger.action.deactivateGroup(GroupObject) - self:T( { "GroupObject Destroyed", GroupObject } ) - end -end - ---- Destroys a @{Dcs.DCSWrapper.Unit#Unit} from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSWrapper.Unit#Unit CleanUpUnit The object to be destroyed. --- @param #string CleanUpUnitName The Unit name ... -function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName ) - self:F( { CleanUpUnit, CleanUpUnitName } ) - - if CleanUpUnit then - local CleanUpGroup = Unit.getGroup(CleanUpUnit) - -- TODO Client bug in 1.5.3 - if CleanUpGroup and CleanUpGroup:isExist() then - local CleanUpGroupUnits = CleanUpGroup:getUnits() - if #CleanUpGroupUnits == 1 then - local CleanUpGroupName = CleanUpGroup:getName() - --self:CreateEventCrash( timer.getTime(), CleanUpUnit ) - CleanUpGroup:destroy() - self:T( { "Destroyed Group:", CleanUpGroupName } ) - else - CleanUpUnit:destroy() - self:T( { "Destroyed Unit:", CleanUpUnitName } ) - end - self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list - CleanUpUnit = nil - end - end -end - --- TODO check Dcs.DCSTypes#Weapon ---- Destroys a missile from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSTypes#Weapon MissileObject -function CLEANUP:_DestroyMissile( MissileObject ) - self:F( { MissileObject } ) - - if MissileObject and MissileObject:isExist() then - MissileObject:destroy() - self:T( "MissileObject Destroyed") - end -end - -function CLEANUP:_OnEventBirth( Event ) - self:F( { Event } ) - - self.CleanUpList[Event.IniDCSUnitName] = {} - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName - - _EVENTDISPATCHER:OnEngineShutDownForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnEngineStartUpForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnHitForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnPilotDeadForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnDeadForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnCrashForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnShotForUnit( Event.IniDCSUnitName, self._EventShot, self ) - - --self:AddEvent( world.event.S_EVENT_ENGINE_SHUTDOWN, self._EventAddForCleanUp ) - --self:AddEvent( world.event.S_EVENT_ENGINE_STARTUP, self._EventAddForCleanUp ) --- self:AddEvent( world.event.S_EVENT_HIT, self._EventAddForCleanUp ) -- , self._EventHitCleanUp ) --- self:AddEvent( world.event.S_EVENT_CRASH, self._EventCrash ) -- , self._EventHitCleanUp ) --- --self:AddEvent( world.event.S_EVENT_DEAD, self._EventCrash ) --- self:AddEvent( world.event.S_EVENT_SHOT, self._EventShot ) --- --- self:EnableEvents() - - -end - ---- Detects if a crash event occurs. --- Crashed units go into a CleanUpList for removal. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventCrash( Event ) - self:F( { Event } ) - - --TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed. - -- self:T("before getGroup") - -- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired - -- self:T("after getGroup") - -- _grp:destroy() - -- self:T("after deactivateGroup") - -- event.initiator:destroy() - - self.CleanUpList[Event.IniDCSUnitName] = {} - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName - -end - ---- Detects if a unit shoots a missile. --- If this occurs within one of the zones, then the weapon used must be destroyed. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventShot( Event ) - self:F( { Event } ) - - -- Test if the missile was fired within one of the CLEANUP.ZoneNames. - local CurrentLandingZoneID = 0 - CurrentLandingZoneID = routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) - if ( CurrentLandingZoneID ) then - -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. - --_SEADmissile:destroy() - SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) - end -end - - ---- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventHitCleanUp( Event ) - self:F( { Event } ) - - if Event.IniDCSUnit then - if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then - self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniDCSUnit:getLife(), "/", Event.IniDCSUnit:getLife0() } ) - if Event.IniDCSUnit:getLife() < Event.IniDCSUnit:getLife0() then - self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName ) - SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) - end - end - end - - if Event.TgtDCSUnit then - if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then - self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtDCSUnit:getLife(), "/", Event.TgtDCSUnit:getLife0() } ) - if Event.TgtDCSUnit:getLife() < Event.TgtDCSUnit:getLife0() then - self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName ) - SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) - end - end - end -end - ---- Add the @{Dcs.DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp. -function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName ) - self:F( { CleanUpUnit, CleanUpUnitName } ) - - self.CleanUpList[CleanUpUnitName] = {} - self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit - self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName - self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit) - self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName() - self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime() - self.CleanUpList[CleanUpUnitName].CleanUpMoved = false - - self:T( { "CleanUp: Add to CleanUpList: ", Unit.getGroup(CleanUpUnit):getName(), CleanUpUnitName } ) - -end - ---- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventAddForCleanUp( Event ) - - if Event.IniDCSUnit then - if self.CleanUpList[Event.IniDCSUnitName] == nil then - if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then - self:_AddForCleanUp( Event.IniDCSUnit, Event.IniDCSUnitName ) - end - end - end - - if Event.TgtDCSUnit then - if self.CleanUpList[Event.TgtDCSUnitName] == nil then - if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then - self:_AddForCleanUp( Event.TgtDCSUnit, Event.TgtDCSUnitName ) - end - end - end - -end - -local CleanUpSurfaceTypeText = { - "LAND", - "SHALLOW_WATER", - "WATER", - "ROAD", - "RUNWAY" - } - ---- At the defined time interval, CleanUp the Groups within the CleanUpList. --- @param #CLEANUP self -function CLEANUP:_CleanUpScheduler() - self:F( { "CleanUp Scheduler" } ) - - local CleanUpCount = 0 - for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do - CleanUpCount = CleanUpCount + 1 - - self:T( { CleanUpUnitName, UnitData } ) - local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName) - local CleanUpGroupName = UnitData.CleanUpGroupName - local CleanUpUnitName = UnitData.CleanUpUnitName - if CleanUpUnit then - self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } ) - if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then - local CleanUpUnitVec3 = CleanUpUnit:getPoint() - --self:T( CleanUpUnitVec3 ) - local CleanUpUnitVec2 = {} - CleanUpUnitVec2.x = CleanUpUnitVec3.x - CleanUpUnitVec2.y = CleanUpUnitVec3.z - --self:T( CleanUpUnitVec2 ) - local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2) - --self:T( CleanUpSurfaceType ) - - if CleanUpUnit and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then - if CleanUpSurfaceType == land.SurfaceType.RUNWAY then - if CleanUpUnit:inAir() then - local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2) - local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight - self:T( { "CleanUp Scheduler", "Height = " .. CleanUpUnitHeight } ) - if CleanUpUnitHeight < 30 then - self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - else - self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - end - end - -- Clean Units which are waiting for a very long time in the CleanUpZone. - if CleanUpUnit then - local CleanUpUnitVelocity = CleanUpUnit:getVelocity() - local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z) - if CleanUpUnitVelocityTotal < 1 then - if UnitData.CleanUpMoved then - if UnitData.CleanUpTime + 180 <= timer.getTime() then - self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - end - else - UnitData.CleanUpTime = timer.getTime() - UnitData.CleanUpMoved = true - end - end - - else - -- Do nothing ... - self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE - end - else - self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." ) - self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE - end - end - self:T(CleanUpCount) - - return true -end - ---- This module contains the SPAWN class. --- --- # 1) @{Functional.Spawn#SPAWN} class, extends @{Core.Base#BASE} --- --- The @{#SPAWN} class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned. --- For each group to be spawned, within the mission editor, a group has to be created with the "late activation flag" set. We call this group the *"Spawn Template"* of the SPAWN object. --- A reference to this Spawn Template needs to be provided when constructing the SPAWN object, by indicating the name of the group within the mission editor in the constructor methods. --- --- Within the SPAWN object, there is an internal index that keeps track of which group from the internal group list was spawned. --- When new groups get spawned by using the SPAWN methods (see below), it will be validated whether the Limits (@{#SPAWN.Limit}) of the SPAWN object are not reached. --- When all is valid, a new group will be created by the spawning methods, and the internal index will be increased with 1. --- --- Regarding the name of new spawned groups, a _SpawnPrefix_ will be assigned for each new group created. --- If you want to have the Spawn Template name to be used as the _SpawnPrefix_ name, use the @{#SPAWN.New} constructor. --- However, when the @{#SPAWN.NewWithAlias} constructor was used, the Alias name will define the _SpawnPrefix_ name. --- Groups will follow the following naming structure when spawned at run-time: --- --- 1. Spawned groups will have the name _SpawnPrefix_#ggg, where ggg is a counter from 0 to 999. --- 2. Spawned units will have the name _SpawnPrefix_#ggg-uu, where uu is a counter from 0 to 99 for each new spawned unit belonging to the group. --- --- Some additional notes that need to be remembered: --- --- * Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the @{#SPAWN} module. --- * It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. --- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. --- --- ## 1.1) SPAWN construction methods --- --- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: --- --- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition). --- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned @{Group} an different name. --- --- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. --- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. --- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. --- --- ## 1.2) SPAWN initialization methods --- --- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix: --- --- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. --- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height. --- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. --- * @{#SPAWN.InitUncontrolled}(): Spawn plane groups uncontrolled. --- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array. --- * @{#SPAWN.InitRepeat}(): Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}. --- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. --- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. --- --- ## 1.3) SPAWN spawning methods --- --- Groups can be spawned at different times and methods: --- --- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index. --- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index. --- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart}() and @{#SPAWN.SpawnScheduleStop}() to start and stop the schedule respectively. --- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). --- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). --- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. --- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. --- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. --- --- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. --- You can use the @{GROUP} object to do further actions with the DCSGroup. --- --- ## 1.4) Retrieve alive GROUPs spawned by the SPAWN object --- --- The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. --- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. --- SPAWN provides methods to iterate through that internal GROUP object reference table: --- --- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found. --- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found. --- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found. --- --- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. --- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive... --- --- ## 1.5) SPAWN object cleaning --- --- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. --- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, --- and it may occur that no new groups are or can be spawned as limits are reached. --- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group. --- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. --- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... --- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. --- This models AI that has succesfully returned to their airbase, to restart their combat activities. --- Check the @{#SPAWN.InitCleanUp}() for further info. --- --- ## 1.6) Catch the @{Group} spawn event in a callback function! --- --- When using the SpawnScheduled method, new @{Group}s are created following the schedule timing parameters. --- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. --- To SPAWN class supports this functionality through the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method, which takes a function as a parameter that you can define locally. --- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. --- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. --- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones )** added. --- --- * This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. --- --- 2016-08-14: SPAWN:**OnSpawnGroup**( SpawnCallBackFunction, ... ) replaces SPAWN:_SpawnFunction_( SpawnCallBackFunction, ... ). --- --- 2016-08-14: SPAWN.SpawnInZone( Zone, __RandomizeGroup__, SpawnIndex ) replaces SpawnInZone( Zone, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromVec3( Vec3, SpawnIndex ) replaces SpawnFromVec3( Vec3, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromVec2( Vec2, SpawnIndex ) replaces SpawnFromVec2( Vec2, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromUnit( SpawnUnit, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromStatic( SpawnStatic, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.**InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius )** added: --- --- * This method enables the randomization of units at the first route point in a radius band at a spawn event. --- --- 2016-08-14: SPAWN.**Init**Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) replaces SPAWN._Limit_( SpawnMaxUnitsAlive, SpawnMaxGroups ): --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) replaces SPAWN._Array_( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) replaces SPAWN._RandomizeRoute_( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**RandomizeTemplate( SpawnTemplatePrefixTable ) replaces SPAWN._RandomizeTemplate_( SpawnTemplatePrefixTable ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**UnControlled() replaces SPAWN._UnControlled_(). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * **Aaron**: Posed the idea for Group position randomization at SpawnInZone and make the Unit randomization separate from the Group randomization. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming --- --- @module Spawn - - - ---- SPAWN Class --- @type SPAWN --- @extends Core.Base#BASE --- @field ClassName --- @field #string SpawnTemplatePrefix --- @field #string SpawnAliasPrefix --- @field #number AliveUnits --- @field #number MaxAliveUnits --- @field #number SpawnIndex --- @field #number MaxAliveGroups --- @field #SPAWN.SpawnZoneTable SpawnZoneTable -SPAWN = { - ClassName = "SPAWN", - SpawnTemplatePrefix = nil, - SpawnAliasPrefix = nil, -} - - ---- @type SPAWN.SpawnZoneTable --- @list SpawnZone - - ---- Creates the main object to spawn a @{Group} defined in the DCS ME. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ) --- @usage local Plane = SPAWN:New( "Plane" ) -- Creates a new local variable that can initiate new planes with the name "Plane#ddd" using the template "Plane" as defined within the ME. -function SPAWN:New( SpawnTemplatePrefix ) - local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN - self:F( { SpawnTemplatePrefix } ) - - local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) - if TemplateGroup then - self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.SpawnIndex = 0 - self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. - self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - - self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. - else - error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) - end - - return self -end - ---- Creates a new SPAWN instance to create new groups based on the defined template and using a new alias for each new group. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. --- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) --- @usage local PlaneWithAlias = SPAWN:NewWithAlias( "Plane", "Bomber" ) -- Creates a new local variable that can instantiate new planes with the name "Bomber#ddd" using the template "Plane" as defined within the ME. -function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } ) - - local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) - if TemplateGroup then - self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.SpawnAliasPrefix = SpawnAliasPrefix - self.SpawnIndex = 0 - self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. - self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - - self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. - else - error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) - end - - return self -end - - ---- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. --- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. --- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... --- When a @{#SPAWN.New} is executed and the limit of the amount of units alive is reached, then no new spawn will happen of the group, until some of these units of the spawn object will be destroyed. --- @param #SPAWN self --- @param #number SpawnMaxUnitsAlive The maximum amount of units that can be alive at runtime. --- @param #number SpawnMaxGroups The maximum amount of groups that can be spawned. When the limit is reached, then no more actual spawns will happen of the group. --- This parameter is useful to define a maximum amount of airplanes, ground troops, helicopters, ships etc within a supply area. --- This parameter accepts the value 0, which defines that there are no maximum group limits, but there are limits on the maximum of units that can be alive at the same time. --- @return #SPAWN self --- @usage --- -- NATO helicopters engaging in the battle field. --- -- This helicopter group consists of one Unit. So, this group will SPAWN maximum 2 groups simultaneously within the DCSRTE. --- -- There will be maximum 24 groups spawned during the whole mission lifetime. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitLimit( 2, 24 ) -function SPAWN:InitLimit( SpawnMaxUnitsAlive, SpawnMaxGroups ) - self:F( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) - - self.SpawnMaxUnitsAlive = SpawnMaxUnitsAlive -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned. - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_InitializeSpawnGroups( SpawnGroupID ) - end - - return self -end - - ---- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. --- @param #SPAWN self --- @param #number SpawnStartPoint is the waypoint where the randomization begins. --- Note that the StartPoint = 0 equaling the point where the group is spawned. --- @param #number SpawnEndPoint is the waypoint where the randomization ends counting backwards. --- This parameter is useful to avoid randomization to end at a waypoint earlier than the last waypoint on the route. --- @param #number SpawnRadius is the radius in meters in which the randomization of the new waypoints, with the original waypoint of the original template located in the middle ... --- @param #number SpawnHeight (optional) Specifies the **additional** height in meters that can be added to the base height specified at each waypoint in the ME. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). --- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. --- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) -function SPAWN:InitRandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) - self:F( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight } ) - - self.SpawnRandomizeRoute = true - self.SpawnRandomizeRouteStartPoint = SpawnStartPoint - self.SpawnRandomizeRouteEndPoint = SpawnEndPoint - self.SpawnRandomizeRouteRadius = SpawnRadius - self.SpawnRandomizeRouteHeight = SpawnHeight - - for GroupID = 1, self.SpawnMaxGroups do - self:_RandomizeRoute( GroupID ) - end - - return self -end - ---- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius. --- @param #SPAWN self --- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius. --- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. --- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). --- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. --- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) -function SPAWN:InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius ) - self:F( { self.SpawnTemplatePrefix, RandomizeUnits, OuterRadius, InnerRadius } ) - - self.SpawnRandomizeUnits = RandomizeUnits or false - self.SpawnOuterRadius = OuterRadius or 0 - self.SpawnInnerRadius = InnerRadius or 0 - - for GroupID = 1, self.SpawnMaxGroups do - self:_RandomizeRoute( GroupID ) - end - - return self -end - ---- This method is rather complicated to understand. But I'll try to explain. --- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor, --- but they will all follow the same Template route and have the same prefix name. --- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group. --- @param #SPAWN self --- @param #string SpawnTemplatePrefixTable A table with the names of the groups defined within the mission editor, from which one will be choosen when a new group will be spawned. --- @return #SPAWN --- @usage --- -- NATO Tank Platoons invading Gori. --- -- Choose between 13 different 'US Tank Platoon' configurations for each new SPAWN the Group to be spawned for the --- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SpawnTemplatePrefixes. --- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and --- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission. --- Spawn_US_Platoon = { 'US Tank Platoon 1', 'US Tank Platoon 2', 'US Tank Platoon 3', 'US Tank Platoon 4', 'US Tank Platoon 5', --- 'US Tank Platoon 6', 'US Tank Platoon 7', 'US Tank Platoon 8', 'US Tank Platoon 9', 'US Tank Platoon 10', --- 'US Tank Platoon 11', 'US Tank Platoon 12', 'US Tank Platoon 13' } --- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) --- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) --- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) -function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable ) - self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) - - self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable - self.SpawnRandomizeTemplate = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_RandomizeTemplate( SpawnGroupID ) - end - - return self -end - ---TODO: Add example. ---- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. --- @param #SPAWN self --- @param #table SpawnZoneTable A table with @{Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Zone}s objects. --- @return #SPAWN --- @usage --- -- NATO Tank Platoons invading Gori. --- -- Choose between 3 different zones for each new SPAWN the Group to be executed, regardless of the zone type. -function SPAWN:InitRandomizeZones( SpawnZoneTable ) - self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } ) - - self.SpawnZoneTable = SpawnZoneTable - self.SpawnRandomizeZones = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_RandomizeZones( SpawnGroupID ) - end - - return self -end - - - - - ---- For planes and helicopters, when these groups go home and land on their home airbases and farps, they normally would taxi to the parking spot, shut-down their engines and wait forever until the Group is removed by the runtime environment. --- This method is used to re-spawn automatically (so no extra call is needed anymore) the same group after it has landed. --- This will enable a spawned group to be re-spawned after it lands, until it is destroyed... --- Note: When the group is respawned, it will re-spawn from the original airbase where it took off. --- So ensure that the routes for groups that respawn, always return to the original airbase, or players may get confused ... --- @param #SPAWN self --- @return #SPAWN self --- @usage --- -- RU Su-34 - AI Ship Attack --- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically. --- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():InitRandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown() -function SPAWN:InitRepeat() - self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) - - self.Repeat = true - self.RepeatOnEngineShutDown = false - self.RepeatOnLanding = true - - return self -end - ---- Respawn group after landing. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitRepeatOnLanding() - self:F( { self.SpawnTemplatePrefix } ) - - self:InitRepeat() - self.RepeatOnEngineShutDown = false - self.RepeatOnLanding = true - - return self -end - - ---- Respawn after landing when its engines have shut down. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitRepeatOnEngineShutDown() - self:F( { self.SpawnTemplatePrefix } ) - - self:InitRepeat() - self.RepeatOnEngineShutDown = true - self.RepeatOnLanding = false - - return self -end - - ---- CleanUp groups when they are still alive, but inactive. --- When groups are still alive and have become inactive due to damage and are unable to contribute anything, then this group will be removed at defined intervals in seconds. --- @param #SPAWN self --- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds. --- @return #SPAWN self --- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive. -function SPAWN:InitCleanUp( SpawnCleanUpInterval ) - self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) - - self.SpawnCleanUpInterval = SpawnCleanUpInterval - self.SpawnCleanUpTimeStamps = {} - - local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() - self:T( { "CleanUp Scheduler:", SpawnGroup } ) - - --self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, SpawnCleanUpInterval ) - self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 ) - return self -end - - - ---- Makes the groups visible before start (like a batallion). --- The method will take the position of the group as the first position in the array. --- @param #SPAWN self --- @param #number SpawnAngle The angle in degrees how the groups and each unit of the group will be positioned. --- @param #number SpawnWidth The amount of Groups that will be positioned on the X axis. --- @param #number SpawnDeltaX The space between each Group on the X-axis. --- @param #number SpawnDeltaY The space between each Group on the Y-axis. --- @return #SPAWN self --- @usage --- -- Define an array of Groups. --- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):InitLimit( 2, 24 ):InitArray( 90, "Diamond", 10, 100, 50 ) -function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) - self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) - - self.SpawnVisible = true -- When the first Spawn executes, all the Groups need to be made visible before start. - - local SpawnX = 0 - local SpawnY = 0 - local SpawnXIndex = 0 - local SpawnYIndex = 0 - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:T( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } ) - - self.SpawnGroups[SpawnGroupID].Visible = true - self.SpawnGroups[SpawnGroupID].Spawned = false - - SpawnXIndex = SpawnXIndex + 1 - if SpawnWidth and SpawnWidth ~= 0 then - if SpawnXIndex >= SpawnWidth then - SpawnXIndex = 0 - SpawnYIndex = SpawnYIndex + 1 - end - end - - local SpawnRootX = self.SpawnGroups[SpawnGroupID].SpawnTemplate.x - local SpawnRootY = self.SpawnGroups[SpawnGroupID].SpawnTemplate.y - - self:_TranslateRotate( SpawnGroupID, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - - self.SpawnGroups[SpawnGroupID].SpawnTemplate.lateActivation = true - self.SpawnGroups[SpawnGroupID].SpawnTemplate.visible = true - - self.SpawnGroups[SpawnGroupID].Visible = true - - _EVENTDISPATCHER:OnBirthForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnBirth, self ) - _EVENTDISPATCHER:OnCrashForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnDeadOrCrash, self ) - - if self.Repeat then - _EVENTDISPATCHER:OnTakeOffForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnTakeOff, self ) - _EVENTDISPATCHER:OnLandForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnLand, self ) - end - if self.RepeatOnEngineShutDown then - _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnEngineShutDown, self ) - end - - self.SpawnGroups[SpawnGroupID].Group = _DATABASE:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) - - SpawnX = SpawnXIndex * SpawnDeltaX - SpawnY = SpawnYIndex * SpawnDeltaY - end - - return self -end - - - ---- Will spawn a group based on the internal index. --- Note: Uses @{DATABASE} module defined in MOOSE. --- @param #SPAWN self --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:Spawn() - self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, self.AliveUnits } ) - - return self:SpawnWithIndex( self.SpawnIndex + 1 ) -end - ---- Will re-spawn a group based on a given index. --- Note: Uses @{DATABASE} module defined in MOOSE. --- @param #SPAWN self --- @param #string SpawnIndex The index of the group to be spawned. --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:ReSpawn( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) - - if not SpawnIndex then - SpawnIndex = 1 - end - --- TODO: This logic makes DCS crash and i don't know why (yet). - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - local WayPoints = SpawnGroup and SpawnGroup.WayPoints or nil - if SpawnGroup then - local SpawnDCSGroup = SpawnGroup:GetDCSObject() - if SpawnDCSGroup then - SpawnGroup:Destroy() - end - end - - local SpawnGroup = self:SpawnWithIndex( SpawnIndex ) - if SpawnGroup and WayPoints then - -- If there were WayPoints set, then Re-Execute those WayPoints! - self:E( WayPoints ) - SpawnGroup:WayPointInitialize( WayPoints ) - SpawnGroup:WayPointExecute( 1, 5 ) - end - - return SpawnGroup -end - ---- Will spawn a group with a specified index number. --- Uses @{DATABASE} global object defined in MOOSE. --- @param #SPAWN self --- @param #string SpawnIndex The index of the group to be spawned. --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:SpawnWithIndex( SpawnIndex ) - self:F2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } ) - - if self:_GetSpawnIndex( SpawnIndex ) then - - if self.SpawnGroups[self.SpawnIndex].Visible then - self.SpawnGroups[self.SpawnIndex].Group:Activate() - else - - local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate - self:T( SpawnTemplate.name ) - - if SpawnTemplate then - - local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y ) - self:T( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } ) - - -- If RandomizeUnits, then Randomize the formation at the start point. - if self.SpawnRandomizeUnits then - for UnitID = 1, #SpawnTemplate.units do - local RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius ) - SpawnTemplate.units[UnitID].x = RandomVec2.x - SpawnTemplate.units[UnitID].y = RandomVec2.y - self:T( 'SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - end - end - end - - _EVENTDISPATCHER:OnBirthForTemplate( SpawnTemplate, self._OnBirth, self ) - _EVENTDISPATCHER:OnCrashForTemplate( SpawnTemplate, self._OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForTemplate( SpawnTemplate, self._OnDeadOrCrash, self ) - - if self.Repeat then - _EVENTDISPATCHER:OnTakeOffForTemplate( SpawnTemplate, self._OnTakeOff, self ) - _EVENTDISPATCHER:OnLandForTemplate( SpawnTemplate, self._OnLand, self ) - end - if self.RepeatOnEngineShutDown then - _EVENTDISPATCHER:OnEngineShutDownForTemplate( SpawnTemplate, self._OnEngineShutDown, self ) - end - self:T3( SpawnTemplate.name ) - - self.SpawnGroups[self.SpawnIndex].Group = _DATABASE:Spawn( SpawnTemplate ) - - -- If there is a SpawnFunction hook defined, call it. - if self.SpawnFunctionHook then - self.SpawnFunctionHook( self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments ) ) - end - -- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats. - --if self.Repeat then - -- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) - --end - end - - self.SpawnGroups[self.SpawnIndex].Spawned = true - return self.SpawnGroups[self.SpawnIndex].Group - else - --self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } ) - end - - return nil -end - ---- Spawns new groups at varying time intervals. --- This is useful if you want to have continuity within your missions of certain (AI) groups to be present (alive) within your missions. --- @param #SPAWN self --- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups. --- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn. --- The variation is a number between 0 and 1, representing the %-tage of variation to be applied on the time interval. --- @return #SPAWN self --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The time interval is set to SPAWN new helicopters between each 600 seconds, with a time variation of 50%. --- -- The time variation in this case will be between 450 seconds and 750 seconds. --- -- This is calculated as follows: --- -- Low limit: 600 * ( 1 - 0.5 / 2 ) = 450 --- -- High limit: 600 * ( 1 + 0.5 / 2 ) = 750 --- -- Between these two values, a random amount of seconds will be choosen for each new spawn of the helicopters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) - self:F( { SpawnTime, SpawnTimeVariation } ) - - if SpawnTime ~= nil and SpawnTimeVariation ~= nil then - self.SpawnScheduler = SCHEDULER:New( self, self._Scheduler, {}, 1, SpawnTime, SpawnTimeVariation ) - end - - return self -end - ---- Will re-start the spawning scheduler. --- Note: This method is only required to be called when the schedule was stopped. -function SPAWN:SpawnScheduleStart() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnScheduler:Start() -end - ---- Will stop the scheduled spawning scheduler. -function SPAWN:SpawnScheduleStop() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnScheduler:Stop() -end - - ---- Allows to place a CallFunction hook when a new group spawns. --- The provided method will be called when a new group is spawned, including its given parameters. --- The first parameter of the SpawnFunction is the @{Wrapper.Group#GROUP} that was spawned. --- @param #SPAWN self --- @param #function SpawnCallBackFunction The function to be called when a group spawns. --- @param SpawnFunctionArguments A random amount of arguments to be provided to the function when the group spawns. --- @return #SPAWN --- @usage --- -- Declare SpawnObject and call a function when a new Group is spawned. --- local SpawnObject = SPAWN --- :New( "SpawnObject" ) --- :InitLimit( 2, 10 ) --- :OnSpawnGroup( --- function( SpawnGroup ) --- SpawnGroup:E( "I am spawned" ) --- end --- ) --- :SpawnScheduled( 300, 0.3 ) -function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... ) - self:F( "OnSpawnGroup" ) - - self.SpawnFunctionHook = SpawnCallBackFunction - self.SpawnFunctionArguments = {} - if arg then - self.SpawnFunctionArguments = arg - end - - return self -end - - ---- Will spawn a group from a Vec3 in 3D space. --- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 coordinates where to spawn the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } ) - - local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) - self:T2(PointVec3) - - if SpawnIndex then - else - SpawnIndex = self.SpawnIndex + 1 - end - - if self:_GetSpawnIndex( SpawnIndex ) then - - local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate - - if SpawnTemplate then - - self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) - - -- Translate the position of the Group Template to the Vec3. - for UnitID = 1, #SpawnTemplate.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - local UnitTemplate = SpawnTemplate.units[UnitID] - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = Vec3.x + ( SX - BX ) - local TY = Vec3.z + ( SY - BY ) - SpawnTemplate.units[UnitID].x = TX - SpawnTemplate.units[UnitID].y = TY - SpawnTemplate.units[UnitID].alt = Vec3.y - self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - end - - SpawnTemplate.route.points[1].x = Vec3.x - SpawnTemplate.route.points[1].y = Vec3.z - SpawnTemplate.route.points[1].alt = Vec3.y - - SpawnTemplate.x = Vec3.x - SpawnTemplate.y = Vec3.z - - return self:SpawnWithIndex( self.SpawnIndex ) - end - end - - return nil -end - ---- Will spawn a group from a Vec2 in 3D space. --- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromVec2( Vec2, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } ) - - local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 ) - return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex ) -end - - ---- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } ) - - if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then - return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex ) - end - - return nil -end - ---- Will spawn a group from a hosting static. This method is mostly advisable to be used if you want to simulate spawning from buldings and structures (static buildings). --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } ) - - if HostStatic and HostStatic:IsAlive() then - return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex ) - end - - return nil -end - ---- Will spawn a Group within a given @{Zone}. --- The @{Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}. --- Once the @{Group} is spawned within the zone, the @{Group} will continue on its route. --- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates. --- @param #SPAWN self --- @param Core.Zone#ZONE Zone The zone where the group is to be spawned. --- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil when nothing was spawned. -function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } ) - - if Zone then - if RandomizeGroup then - return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex ) - else - return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex ) - end - end - - return nil -end - ---- (AIR) Will spawn a plane group in uncontrolled mode... --- This will be similar to the uncontrolled flag setting in the ME. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitUnControlled() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnUnControlled = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self.SpawnGroups[SpawnGroupID].UnControlled = true - end - - return self -end - - - ---- Will return the SpawnGroupName either with with a specific count number or without any count. --- @param #SPAWN self --- @param #number SpawnIndex Is the number of the Group that is to be spawned. --- @return #string SpawnGroupName -function SPAWN:SpawnGroupName( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) - - local SpawnPrefix = self.SpawnTemplatePrefix - if self.SpawnAliasPrefix then - SpawnPrefix = self.SpawnAliasPrefix - end - - if SpawnIndex then - local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex ) - self:T( SpawnName ) - return SpawnName - else - self:T( SpawnPrefix ) - return SpawnPrefix - end - -end - ---- Will find the first alive @{Group} it has spawned, and return the alive @{Group} object and the first Index where the first alive @{Group} object has been found. --- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The @{Group} object found, the new Index where the group was found. --- @return #nil, #nil When no group is found, #nil is returned. --- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() --- while GroupPlane ~= nil do --- -- Do actions with the GroupPlane object. --- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) --- end -function SPAWN:GetFirstAliveGroup() - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - for SpawnIndex = 1, self.SpawnCount do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - return SpawnGroup, SpawnIndex - end - end - - return nil, nil -end - - ---- Will find the next alive @{Group} object from a given Index, and return a reference to the alive @{Group} object and the next Index where the alive @{Group} has been found. --- @param #SPAWN self --- @param #number SpawnIndexStart A Index holding the start position to search from. This method can also be used to find the first alive @{Group} object from the given Index. --- @return Wrapper.Group#GROUP, #number The next alive @{Group} object found, the next Index where the next alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found from the start Index position, #nil is returned. --- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() --- while GroupPlane ~= nil do --- -- Do actions with the GroupPlane object. --- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) --- end -function SPAWN:GetNextAliveGroup( SpawnIndexStart ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndexStart } ) - - SpawnIndexStart = SpawnIndexStart + 1 - for SpawnIndex = SpawnIndexStart, self.SpawnCount do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - return SpawnGroup, SpawnIndex - end - end - - return nil, nil -end - ---- Will find the last alive @{Group} object, and will return a reference to the last live @{Group} object and the last Index where the last alive @{Group} object has been found. --- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The last alive @{Group} object found, the last Index where the last alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found, #nil is returned. --- @usage --- -- Find the last alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetLastAliveGroup() --- if GroupPlane then -- GroupPlane can be nil!!! --- -- Do actions with the GroupPlane object. --- end -function SPAWN:GetLastAliveGroup() - self:F( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) - - self.SpawnIndex = self:_GetLastIndex() - for SpawnIndex = self.SpawnIndex, 1, -1 do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - self.SpawnIndex = SpawnIndex - return SpawnGroup - end - end - - self.SpawnIndex = nil - return nil -end - - - ---- Get the group from an index. --- Returns the group from the SpawnGroups list. --- If no index is given, it will return the first group in the list. --- @param #SPAWN self --- @param #number SpawnIndex The index of the group to return. --- @return Wrapper.Group#GROUP self -function SPAWN:GetGroupFromIndex( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) - - if not SpawnIndex then - SpawnIndex = 1 - end - - if self.SpawnGroups and self.SpawnGroups[SpawnIndex] then - local SpawnGroup = self.SpawnGroups[SpawnIndex].Group - return SpawnGroup - else - return nil - end -end - ---- Get the group index from a DCSUnit. --- The method will search for a #-mark, and will return the index behind the #-mark of the DCSUnit. --- It will return nil of no prefix was found. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit The @{DCSUnit} to be searched. --- @return #string The prefix --- @return #nil Nothing found -function SPAWN:_GetGroupIndexFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local SpawnUnitName = ( DCSUnit and DCSUnit:getName() ) or nil - if SpawnUnitName then - local IndexString = string.match( SpawnUnitName, "#.*-" ):sub( 2, -2 ) - if IndexString then - local Index = tonumber( IndexString ) - return Index - end - end - - return nil -end - ---- Return the prefix of a SpawnUnit. --- The method will search for a #-mark, and will return the text before the #-mark. --- It will return nil of no prefix was found. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#UNIT DCSUnit The @{DCSUnit} to be searched. --- @return #string The prefix --- @return #nil Nothing found -function SPAWN:_GetPrefixFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local DCSUnitName = ( DCSUnit and DCSUnit:getName() ) or nil - if DCSUnitName then - local SpawnPrefix = string.match( DCSUnitName, ".*#" ) - if SpawnPrefix then - SpawnPrefix = SpawnPrefix:sub( 1, -2 ) - end - return SpawnPrefix - end - - return nil -end - ---- Return the group within the SpawnGroups collection with input a DCSUnit. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit The @{DCSUnit} to be searched. --- @return Wrapper.Group#GROUP The Group --- @return #nil Nothing found -function SPAWN:_GetGroupFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local SpawnPrefix = self:_GetPrefixFromDCSUnit( DCSUnit ) - - if self.SpawnTemplatePrefix == SpawnPrefix or ( self.SpawnAliasPrefix and self.SpawnAliasPrefix == SpawnPrefix ) then - local SpawnGroupIndex = self:_GetGroupIndexFromDCSUnit( DCSUnit ) - local SpawnGroup = self.SpawnGroups[SpawnGroupIndex].Group - self:T( SpawnGroup ) - return SpawnGroup - end - - return nil -end - - ---- Get the index from a given group. --- The function will search the name of the group for a #, and will return the number behind the #-mark. -function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) - - local IndexString = string.match( SpawnGroup:GetName(), "#.*$" ):sub( 2 ) - local Index = tonumber( IndexString ) - - self:T3( IndexString, Index ) - return Index - -end - ---- Return the last maximum index that can be used. -function SPAWN:_GetLastIndex() - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - return self.SpawnMaxGroups -end - ---- Initalize the SpawnGroups collection. -function SPAWN:_InitializeSpawnGroups( SpawnIndex ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) - - if not self.SpawnGroups[SpawnIndex] then - self.SpawnGroups[SpawnIndex] = {} - self.SpawnGroups[SpawnIndex].Visible = false - self.SpawnGroups[SpawnIndex].Spawned = false - self.SpawnGroups[SpawnIndex].UnControlled = false - self.SpawnGroups[SpawnIndex].SpawnTime = 0 - - self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefix - self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) - end - - self:_RandomizeTemplate( SpawnIndex ) - self:_RandomizeRoute( SpawnIndex ) - --self:_TranslateRotate( SpawnIndex ) - - return self.SpawnGroups[SpawnIndex] -end - - - ---- Gets the CategoryID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCategoryID( SpawnPrefix ) - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - return TemplateGroup:getCategory() - else - return nil - end -end - ---- Gets the CoalitionID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCoalitionID( SpawnPrefix ) - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - return TemplateGroup:getCoalition() - else - return nil - end -end - ---- Gets the CountryID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCountryID( SpawnPrefix ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) - - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - local TemplateUnits = TemplateGroup:getUnits() - return TemplateUnits[1]:getCountry() - else - return nil - end -end - ---- Gets the Group Template from the ME environment definition. --- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix --- @return @SPAWN self -function SPAWN:_GetTemplate( SpawnTemplatePrefix ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) - - local SpawnTemplate = nil - - SpawnTemplate = routines.utils.deepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template ) - - if SpawnTemplate == nil then - error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) - end - - --SpawnTemplate.SpawnCoalitionID = self:_GetGroupCoalitionID( SpawnTemplatePrefix ) - --SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnTemplatePrefix ) - --SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnTemplatePrefix ) - - self:T3( { SpawnTemplate } ) - return SpawnTemplate -end - ---- Prepares the new Group Template. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) - SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) - - SpawnTemplate.groupId = nil - --SpawnTemplate.lateActivation = false - SpawnTemplate.lateActivation = false - - if SpawnTemplate.CategoryID == Group.Category.GROUND then - self:T3( "For ground units, visible needs to be false..." ) - SpawnTemplate.visible = false - end - - if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then - SpawnTemplate.uncontrolled = false - end - - for UnitID = 1, #SpawnTemplate.units do - SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID ) - SpawnTemplate.units[UnitID].unitId = nil - end - - self:T3( { "Template:", SpawnTemplate } ) - return SpawnTemplate - -end - ---- Private method randomizing the routes. --- @param #SPAWN self --- @param #number SpawnIndex The index of the group to be spawned. --- @return #SPAWN -function SPAWN:_RandomizeRoute( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) - - if self.SpawnRandomizeRoute then - local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate - local RouteCount = #SpawnTemplate.route.points - - for t = self.SpawnRandomizeRouteStartPoint + 1, ( RouteCount - self.SpawnRandomizeRouteEndPoint ) do - - SpawnTemplate.route.points[t].x = SpawnTemplate.route.points[t].x + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) - SpawnTemplate.route.points[t].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) - - -- Manage randomization of altitude for airborne units ... - if SpawnTemplate.CategoryID == Group.Category.AIRPLANE or SpawnTemplate.CategoryID == Group.Category.HELICOPTER then - if SpawnTemplate.route.points[t].alt and self.SpawnRandomizeRouteHeight then - SpawnTemplate.route.points[t].alt = SpawnTemplate.route.points[t].alt + math.random( 1, self.SpawnRandomizeRouteHeight ) - end - else - SpawnTemplate.route.points[t].alt = nil - end - - self:T( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y ) - end - end - - self:_RandomizeZones( SpawnIndex ) - - return self -end - ---- Private method that randomizes the template of the group. --- @param #SPAWN self --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_RandomizeTemplate( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeTemplate } ) - - if self.SpawnRandomizeTemplate then - self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] - self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) - self.SpawnGroups[SpawnIndex].SpawnTemplate.route = routines.utils.deepCopy( self.SpawnTemplate.route ) - self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x - self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y - self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time - for UnitID = 1, #self.SpawnGroups[SpawnIndex].SpawnTemplate.units do - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].heading = self.SpawnTemplate.units[1].heading - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x = self.SpawnTemplate.units[1].x - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y = self.SpawnTemplate.units[1].y - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].alt = self.SpawnTemplate.units[1].alt - end - end - - self:_RandomizeRoute( SpawnIndex ) - - return self -end - ---- Private method that randomizes the @{Zone}s where the Group will be spawned. --- @param #SPAWN self --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_RandomizeZones( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } ) - - if self.SpawnRandomizeZones then - local SpawnZone = nil -- Core.Zone#ZONE_BASE - while not SpawnZone do - self:T( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } ) - local ZoneID = math.random( #self.SpawnZoneTable ) - self:T( ZoneID ) - SpawnZone = self.SpawnZoneTable[ ZoneID ]:GetZoneMaybe() - end - - self:T( "Preparing Spawn in Zone", SpawnZone:GetName() ) - - local SpawnVec2 = SpawnZone:GetRandomVec2() - - self:T( { SpawnVec2 = SpawnVec2 } ) - - local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate - - self:T( { Route = SpawnTemplate.route } ) - - for UnitID = 1, #SpawnTemplate.units do - local UnitTemplate = SpawnTemplate.units[UnitID] - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = SpawnVec2.x + ( SX - BX ) - local TY = SpawnVec2.y + ( SY - BY ) - UnitTemplate.x = TX - UnitTemplate.y = TY - -- TODO: Manage altitude based on landheight... - --SpawnTemplate.units[UnitID].alt = SpawnVec2: - self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) - end - SpawnTemplate.x = SpawnVec2.x - SpawnTemplate.y = SpawnVec2.y - SpawnTemplate.route.points[1].x = SpawnVec2.x - SpawnTemplate.route.points[1].y = SpawnVec2.y - end - - return self - -end - -function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) - - -- Translate - local TranslatedX = SpawnX - local TranslatedY = SpawnY - - -- Rotate - -- From Wikipedia: https://en.wikipedia.org/wiki/Rotation_matrix#Common_rotations - -- x' = x \cos \theta - y \sin \theta\ - -- y' = x \sin \theta + y \cos \theta\ - local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) - + TranslatedY * math.sin( math.rad( SpawnAngle ) ) - local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) - + TranslatedY * math.cos( math.rad( SpawnAngle ) ) - - -- Assign - self.SpawnGroups[SpawnIndex].SpawnTemplate.x = SpawnRootX - RotatedX - self.SpawnGroups[SpawnIndex].SpawnTemplate.y = SpawnRootY + RotatedY - - - local SpawnUnitCount = table.getn( self.SpawnGroups[SpawnIndex].SpawnTemplate.units ) - for u = 1, SpawnUnitCount do - - -- Translate - local TranslatedX = SpawnX - local TranslatedY = SpawnY - 10 * ( u - 1 ) - - -- Rotate - local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) - + TranslatedY * math.sin( math.rad( SpawnAngle ) ) - local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) - + TranslatedY * math.cos( math.rad( SpawnAngle ) ) - - -- Assign - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].x = SpawnRootX - RotatedX - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].y = SpawnRootY + RotatedY - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading + math.rad( SpawnAngle ) - end - - return self -end - ---- Get the next index of the groups to be spawned. This method is complicated, as it is used at several spaces. -function SPAWN:_GetSpawnIndex( SpawnIndex ) - self:F2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) - - if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then - if ( self.SpawnMaxUnitsAlive == 0 ) or ( self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive ) or self.UnControlled == true then - if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then - self.SpawnCount = self.SpawnCount + 1 - SpawnIndex = self.SpawnCount - end - self.SpawnIndex = SpawnIndex - if not self.SpawnGroups[self.SpawnIndex] then - self:_InitializeSpawnGroups( self.SpawnIndex ) - end - else - return nil - end - else - return nil - end - - return self.SpawnIndex -end - - --- TODO Need to delete this... _DATABASE does this now ... - ---- @param #SPAWN self --- @param Core.Event#EVENTDATA Event -function SPAWN:_OnBirth( Event ) - - if timer.getTime0() < timer.getAbsTime() then - if Event.IniDCSUnit then - local EventPrefix = self:_GetPrefixFromDCSUnit( Event.IniDCSUnit ) - self:T( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits + 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end - end - end - -end - ---- Obscolete --- @todo Need to delete this... _DATABASE does this now ... - ---- @param #SPAWN self --- @param Core.Event#EVENTDATA Event -function SPAWN:_OnDeadOrCrash( Event ) - self:F( self.SpawnTemplatePrefix, Event ) - - if Event.IniDCSUnit then - local EventPrefix = self:_GetPrefixFromDCSUnit( Event.IniDCSUnit ) - self:T( { "Dead event: " .. EventPrefix, self.SpawnTemplatePrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits - 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end - end -end - ---- Will detect AIR Units taking off... When the event takes place, the spawned Group is registered as airborne... --- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups. --- @todo Need to test for AIR Groups only... -function SPAWN:_OnTakeOff( event ) - self:F( self.SpawnTemplatePrefix, event ) - - if event.initiator and event.initiator:getName() then - local SpawnGroup = self:_GetGroupFromDCSUnit( event.initiator ) - if SpawnGroup then - self:T( { "TakeOff event: " .. event.initiator:getName(), event } ) - self:T( "self.Landed = false" ) - self.Landed = false - end - end -end - ---- Will detect AIR Units landing... When the event takes place, the spawned Group is registered as landed. --- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups. --- @todo Need to test for AIR Groups only... -function SPAWN:_OnLand( event ) - self:F( self.SpawnTemplatePrefix, event ) - - local SpawnUnit = event.initiator - if SpawnUnit and SpawnUnit:isExist() and Object.getCategory(SpawnUnit) == Object.Category.UNIT then - local SpawnGroup = self:_GetGroupFromDCSUnit( SpawnUnit ) - if SpawnGroup then - self:T( { "Landed event:" .. SpawnUnit:getName(), event } ) - self.Landed = true - self:T( "self.Landed = true" ) - if self.Landed and self.RepeatOnLanding then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end - end -end - ---- Will detect AIR Units shutting down their engines ... --- When the event takes place, and the method @{RepeatOnEngineShutDown} was called, the spawned Group will Re-SPAWN. --- But only when the Unit was registered to have landed. --- @param #SPAWN self --- @see _OnTakeOff --- @see _OnLand --- @todo Need to test for AIR Groups only... -function SPAWN:_OnEngineShutDown( event ) - self:F( self.SpawnTemplatePrefix, event ) - - local SpawnUnit = event.initiator - if SpawnUnit and SpawnUnit:isExist() and Object.getCategory(SpawnUnit) == Object.Category.UNIT then - local SpawnGroup = self:_GetGroupFromDCSUnit( SpawnUnit ) - if SpawnGroup then - self:T( { "EngineShutDown event: " .. SpawnUnit:getName(), event } ) - if self.Landed and self.RepeatOnEngineShutDown then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end - end -end - ---- This function is called automatically by the Spawning scheduler. --- It is the internal worker method SPAWNing new Groups on the defined time intervals. -function SPAWN:_Scheduler() - self:F2( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) - - -- Validate if there are still groups left in the batch... - self:Spawn() - - return true -end - ---- Schedules the CleanUp of Groups --- @param #SPAWN self --- @return #boolean True = Continue Scheduler -function SPAWN:_SpawnCleanUpScheduler() - self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) - - local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() - self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) - - while SpawnGroup do - - local SpawnUnits = SpawnGroup:GetUnits() - - for UnitID, UnitData in pairs( SpawnUnits ) do - - local SpawnUnit = UnitData -- Wrapper.Unit#UNIT - local SpawnUnitName = SpawnUnit:GetName() - - - self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {} - local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] - self:T( { SpawnUnitName, Stamp } ) - - if Stamp.Vec2 then - if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then - local NewVec2 = SpawnUnit:GetVec2() - if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then - -- If the plane is not moving, and is on the ground, assign it with a timestamp... - if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Vec2 = nil - Stamp.Time = nil - end - else - Stamp.Time = timer.getTime() - Stamp.Vec2 = SpawnUnit:GetVec2() - end - else - Stamp.Vec2 = nil - Stamp.Time = nil - end - else - if SpawnUnit:InAir() == false then - Stamp.Vec2 = SpawnUnit:GetVec2() - if SpawnUnit:GetVelocityKMH() < 1 then - Stamp.Time = timer.getTime() - end - else - Stamp.Time = nil - Stamp.Vec2 = nil - end - end - end - - SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor ) - - self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) - - end - - return true -- Repeat - -end ---- Limit the simultaneous movement of Groups within a running Mission. --- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles. --- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if --- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units --- on defined intervals (currently every minute). --- @module MOVEMENT - ---- the MOVEMENT class --- @type -MOVEMENT = { - ClassName = "MOVEMENT", -} - ---- Creates the main object which is handling the GROUND forces movement. --- @param table{string,...}|string MovePrefixes is a table of the Prefixes (names) of the GROUND Groups that need to be controlled by the MOVEMENT Object. --- @param number MoveMaximum is a number that defines the maximum amount of GROUND Units to be moving during one minute. --- @return MOVEMENT --- @usage --- -- Limit the amount of simultaneous moving units on the ground to prevent lag. --- Movement_US_Platoons = MOVEMENT:New( { 'US Tank Platoon Left', 'US Tank Platoon Middle', 'US Tank Platoon Right', 'US CH-47D Troops' }, 15 ) - -function MOVEMENT:New( MovePrefixes, MoveMaximum ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { MovePrefixes, MoveMaximum } ) - - if type( MovePrefixes ) == 'table' then - self.MovePrefixes = MovePrefixes - else - self.MovePrefixes = { MovePrefixes } - end - self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart. - self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move... - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not. - - _EVENTDISPATCHER:OnBirth( self.OnBirth, self ) - --- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth ) --- --- self:EnableEvents() - - self:ScheduleStart() - - return self -end - ---- Call this function to start the MOVEMENT scheduling. -function MOVEMENT:ScheduleStart() - self:F() - --self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) - self.MoveFunction = SCHEDULER:New( self, self._Scheduler, {}, 1, 120 ) -end - ---- Call this function to stop the MOVEMENT scheduling. --- @todo need to implement it ... Forgot. -function MOVEMENT:ScheduleStop() - self:F() - -end - ---- Captures the birth events when new Units were spawned. --- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. -function MOVEMENT:OnBirth( Event ) - self:F( { Event } ) - - if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line - if Event.IniDCSUnit then - self:T( "Birth object : " .. Event.IniDCSUnitName ) - if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then - for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do - if string.find( Event.IniDCSUnitName, MovePrefix, 1, true ) then - self.AliveUnits = self.AliveUnits + 1 - self.MoveUnits[Event.IniDCSUnitName] = Event.IniDCSGroupName - self:T( self.AliveUnits ) - end - end - end - end - _EVENTDISPATCHER:OnCrashForUnit( Event.IniDCSUnitName, self.OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForUnit( Event.IniDCSUnitName, self.OnDeadOrCrash, self ) - end - -end - ---- Captures the Dead or Crash events when Units crash or are destroyed. --- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. -function MOVEMENT:OnDeadOrCrash( Event ) - self:F( { Event } ) - - if Event.IniDCSUnit then - self:T( "Dead object : " .. Event.IniDCSUnitName ) - for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do - if string.find( Event.IniDCSUnitName, MovePrefix, 1, true ) then - self.AliveUnits = self.AliveUnits - 1 - self.MoveUnits[Event.IniDCSUnitName] = nil - self:T( self.AliveUnits ) - end - end - end -end - ---- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true. -function MOVEMENT:_Scheduler() - self:F( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) - - if self.AliveUnits > 0 then - local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits - self:T( 'Move Probability = ' .. MoveProbability ) - - for MovementUnitName, MovementGroupName in pairs( self.MoveUnits ) do - local MovementGroup = Group.getByName( MovementGroupName ) - if MovementGroup and MovementGroup:isExist() then - local MoveOrStop = math.random( 1, 100 ) - self:T( 'MoveOrStop = ' .. MoveOrStop ) - if MoveOrStop <= MoveProbability then - self:T( 'Group continues moving = ' .. MovementGroupName ) - trigger.action.groupContinueMoving( MovementGroup ) - else - self:T( 'Group stops moving = ' .. MovementGroupName ) - trigger.action.groupStopMoving( MovementGroup ) - end - else - self.MoveUnits[MovementUnitName] = nil - end - end - end - return true -end ---- Provides defensive behaviour to a set of SAM sites within a running Mission. --- @module Sead --- @author to be searched on the forum --- @author (co) Flightcontrol (Modified and enriched with functionality) - ---- The SEAD class --- @type SEAD --- @extends Core.Base#BASE -SEAD = { - ClassName = "SEAD", - TargetSkill = { - Average = { Evade = 50, DelayOff = { 10, 25 }, DelayOn = { 10, 30 } } , - Good = { Evade = 30, DelayOff = { 8, 20 }, DelayOn = { 20, 40 } } , - High = { Evade = 15, DelayOff = { 5, 17 }, DelayOn = { 30, 50 } } , - Excellent = { Evade = 10, DelayOff = { 3, 10 }, DelayOn = { 30, 60 } } - }, - SEADGroupPrefixes = {} -} - ---- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. --- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions... --- Chances are big that the missile will miss. --- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCSRTE on which evasive actions need to be taken. --- @return SEAD --- @usage --- -- CCCP SEAD Defenses --- -- Defends the Russian SA installations from SEAD attacks. --- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) -function SEAD:New( SEADGroupPrefixes ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( SEADGroupPrefixes ) - if type( SEADGroupPrefixes ) == 'table' then - for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do - self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix - end - else - self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes - end - _EVENTDISPATCHER:OnShot( self.EventShot, self ) - - return self -end - ---- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. --- @see SEAD -function SEAD:EventShot( Event ) - self:F( { Event } ) - - local SEADUnit = Event.IniDCSUnit - local SEADUnitName = Event.IniDCSUnitName - local SEADWeapon = Event.Weapon -- Identify the weapon fired - local SEADWeaponName = Event.WeaponName -- return weapon type - -- Start of the 2nd loop - self:T( "Missile Launched = " .. SEADWeaponName ) - if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD - local _evade = math.random (1,100) -- random number for chance of evading action - local _targetMim = Event.Weapon:getTarget() -- Identify target - local _targetMimname = Unit.getName(_targetMim) - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimgroupName = _targetMimgroup:getName() - local _targetMimcont= _targetMimgroup:getController() - local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill - self:T( self.SEADGroupPrefixes ) - self:T( _targetMimgroupName ) - local SEADGroupFound = false - for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do - if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then - SEADGroupFound = true - self:T( 'Group Found' ) - break - end - end - if SEADGroupFound == true then - if _targetskill == "Random" then -- when skill is random, choose a skill - local Skills = { "Average", "Good", "High", "Excellent" } - _targetskill = Skills[ math.random(1,4) ] - end - self:T( _targetskill ) - if self.TargetSkill[_targetskill] then - if (_evade > self.TargetSkill[_targetskill].Evade) then - self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) - local _targetMim = Weapon.getTarget(SEADWeapon) - local _targetMimname = Unit.getName(_targetMim) - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimcont= _targetMimgroup:getController() - routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly - local SuppressedGroups1 = {} -- unit suppressed radar off for a random time - local function SuppressionEnd1(id) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - SuppressedGroups1[id.groupName] = nil - end - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2]) - if SuppressedGroups1[id.groupName] == nil then - SuppressedGroups1[id.groupName] = { - SuppressionEndTime1 = timer.getTime() + delay1, - SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function - } - Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20) - end - - local SuppressedGroups = {} - local function SuppressionEnd(id) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) - SuppressedGroups[id.groupName] = nil - end - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) - if SuppressedGroups[id.groupName] == nil then - SuppressedGroups[id.groupName] = { - SuppressionEndTime = timer.getTime() + delay, - SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function - } - timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20) - end - end - end - end - end -end ---- Taking the lead of AI escorting your flight. --- --- @{#ESCORT} class --- ================ --- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead. --- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). --- --- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. --- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. --- --- RADIO MENUs that can be created: --- ================================ --- Find a summary below of the current available commands: --- --- Navigation ...: --- --------------- --- Escort group navigation functions: --- --- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. --- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. --- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. --- --- Hold position ...: --- ------------------ --- Escort group navigation functions: --- --- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- --- Report targets ...: --- ------------------- --- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). --- --- * **"Report now":** Will report the current detected targets. --- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. --- * **"Report targets off":** Will stop detecting targets. --- --- Scan targets ...: --- ----------------- --- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. --- --- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. --- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. --- --- Attack targets ...: --- ------------------- --- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. --- --- Request assistance from ...: --- ---------------------------- --- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. --- This menu item allows to request attack support from other escorts supporting the current client group. --- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. --- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. --- --- ROE ...: --- -------- --- Sets the Rules of Engagement (ROE) of the escort group when in flight. --- --- * **"Hold Fire":** The escort group will hold fire. --- * **"Return Fire":** The escort group will return fire. --- * **"Open Fire":** The escort group will open fire on designated targets. --- * **"Weapon Free":** The escort group will engage with any target. --- --- Evasion ...: --- ------------ --- Will define the evasion techniques that the escort group will perform during flight or combat. --- --- * **"Fight until death":** The escort group will have no reaction to threats. --- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed. --- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. --- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. --- --- Resume Mission ...: --- ------------------- --- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. --- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. --- --- ESCORT construction methods. --- ============================ --- Create a new SPAWN object with the @{#ESCORT.New} method: --- --- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. --- --- ESCORT initialization methods. --- ============================== --- The following menus are created within the RADIO MENU of an active unit hosted by a player: --- --- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client. --- * @{#ESCORT.MenuHoldAtEscortPosition}: Creates a menu to hold the escort at its current position. --- * @{#ESCORT.MenuHoldAtLeaderPosition}: Creates a menu to hold the escort at the client position. --- * @{#ESCORT.MenuScanForTargets}: Creates a menu so that the escort scans targets. --- * @{#ESCORT.MenuFlare}: Creates a menu to disperse flares. --- * @{#ESCORT.MenuSmoke}: Creates a menu to disparse smoke. --- * @{#ESCORT.MenuReportTargets}: Creates a menu so that the escort reports targets. --- * @{#ESCORT.MenuReportPosition}: Creates a menu so that the escort reports its current position from bullseye. --- * @{#ESCORT.MenuAssistedAttack: Creates a menu so that the escort supportes assisted attack from other escorts with the client. --- * @{#ESCORT.MenuROE: Creates a menu structure to set the rules of engagement of the escort. --- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat. --- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint. --- --- --- @usage --- -- Declare a new EscortPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. --- --- -- Now use these 2 objects to construct the new EscortPlanes object. --- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) --- --- --- --- @module Escort --- @author FlightControl - ---- ESCORT class --- @type ESCORT --- @extends Core.Base#BASE --- @field Wrapper.Client#CLIENT EscortClient --- @field Wrapper.Group#GROUP EscortGroup --- @field #string EscortName --- @field #ESCORT.MODE EscortMode The mode the escort is in. --- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. --- @field #number FollowDistance The current follow distance. --- @field #boolean ReportTargets If true, nearby targets are reported. --- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. --- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. --- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission -ESCORT = { - ClassName = "ESCORT", - EscortName = nil, -- The Escort Name - EscortClient = nil, - EscortGroup = nil, - EscortMode = 1, - MODE = { - FOLLOW = 1, - MISSION = 2, - }, - Targets = {}, -- The identified targets - FollowScheduler = nil, - ReportTargets = true, - OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, - OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, - SmokeDirectionVector = false, - TaskPoints = {} -} - ---- ESCORT.Mode class --- @type ESCORT.MODE --- @field #number FOLLOW --- @field #number MISSION - ---- MENUPARAM type --- @type MENUPARAM --- @field #ESCORT ParamSelf --- @field #Distance ParamDistance --- @field #function ParamFunction --- @field #string ParamMessage - ---- ESCORT class constructor for an AI group --- @param #ESCORT self --- @param Wrapper.Client#CLIENT EscortClient The client escorted by the EscortGroup. --- @param Wrapper.Group#GROUP EscortGroup The group AI escorting the EscortClient. --- @param #string EscortName Name of the escort. --- @param #string EscortBriefing A text showing the ESCORT briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. --- @return #ESCORT self --- @usage --- -- Declare a new EscortPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. --- --- -- Now use these 2 objects to construct the new EscortPlanes object. --- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) -function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { EscortClient, EscortGroup, EscortName } ) - - self.EscortClient = EscortClient -- Wrapper.Client#CLIENT - self.EscortGroup = EscortGroup -- Wrapper.Group#GROUP - self.EscortName = EscortName - self.EscortBriefing = EscortBriefing - - -- Set EscortGroup known at EscortClient. - if not self.EscortClient._EscortGroups then - self.EscortClient._EscortGroups = {} - end - - if not self.EscortClient._EscortGroups[EscortGroup:GetName()] then - self.EscortClient._EscortGroups[EscortGroup:GetName()] = {} - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName - self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {} - end - - self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName ) - - self.EscortGroup:WayPointInitialize(1) - - self.EscortGroup:OptionROTVertical() - self.EscortGroup:OptionROEOpenFire() - - if not EscortBriefing then - EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. - "We're escorting your flight. " .. - "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n", - 60, EscortClient - ) - else - EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") " .. EscortBriefing, - 60, EscortClient - ) - end - - self.FollowDistance = 100 - self.CT1 = 0 - self.GT1 = 0 - self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 ) - self.EscortMode = ESCORT.MODE.MISSION - self.FollowScheduler:Stop() - - return self -end - ---- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to. --- This allows to visualize where the escort is flying to. --- @param #ESCORT self --- @param #boolean SmokeDirection If true, then the direction vector will be smoked. -function ESCORT:TestSmokeDirectionVector( SmokeDirection ) - self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false -end - - ---- Defines the default menus --- @param #ESCORT self --- @return #ESCORT -function ESCORT:Menus() - self:F() - - self:MenuFollowAt( 100 ) - self:MenuFollowAt( 200 ) - self:MenuFollowAt( 300 ) - self:MenuFollowAt( 400 ) - - self:MenuScanForTargets( 100, 60 ) - - self:MenuHoldAtEscortPosition( 30 ) - self:MenuHoldAtLeaderPosition( 30 ) - - self:MenuFlare() - self:MenuSmoke() - - self:MenuReportTargets( 60 ) - self:MenuAssistedAttack() - self:MenuROE() - self:MenuEvasion() - self:MenuResumeMission() - - - return self -end - - - ---- Defines a menu slot to let the escort Join and Follow you at a certain distance. --- This menu will appear under **Navigation**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client. --- @return #ESCORT -function ESCORT:MenuFollowAt( Distance ) - self:F(Distance) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - if not self.EscortMenuJoinUpAndFollow then - self.EscortMenuJoinUpAndFollow = {} - end - - self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = Distance } ) - - self.EscortMode = ESCORT.MODE.FOLLOW - end - - return self -end - ---- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. --- This menu will appear under **Hold position**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT --- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. -function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - - if not self.EscortMenuHold then - self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) - end - - if not Height then - Height = 30 - end - - if not Seconds then - Seconds = 0 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "Hold at %d meter", Height ) - else - MenuText = string.format( "Hold at %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuHoldPosition then - self.EscortMenuHoldPosition = {} - end - - self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuHold, - ESCORT._HoldPosition, - { ParamSelf = self, - ParamOrbitGroup = self.EscortGroup, - ParamHeight = Height, - ParamSeconds = Seconds - } - ) - end - - return self -end - - ---- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. --- This menu will appear under **Navigation**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT --- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. -function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - - if not self.EscortMenuHold then - self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) - end - - if not Height then - Height = 30 - end - - if not Seconds then - Seconds = 0 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "Rejoin and hold at %d meter", Height ) - else - MenuText = string.format( "Rejoin and hold at %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuHoldAtLeaderPosition then - self.EscortMenuHoldAtLeaderPosition = {} - end - - self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuHold, - ESCORT._HoldPosition, - { ParamSelf = self, - ParamOrbitGroup = self.EscortClient, - ParamHeight = Height, - ParamSeconds = Seconds - } - ) - end - - return self -end - ---- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds. --- This menu will appear under **Scan targets**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuScan then - self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu ) - end - - if not Height then - Height = 100 - end - - if not Seconds then - Seconds = 30 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "At %d meter", Height ) - else - MenuText = string.format( "At %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuScanForTargets then - self.EscortMenuScanForTargets = {} - end - - self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuScan, - ESCORT._ScanTargets, - { ParamSelf = self, - ParamScanDuration = 30 - } - ) - end - - return self -end - - - ---- Defines a menu slot to let the escort disperse a flare in a certain color. --- This menu will appear under **Navigation**. --- The flare will be fired from the first unit in the group. --- @param #ESCORT self --- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuFlare( MenuTextFormat ) - self:F() - - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Flare" - else - MenuText = MenuTextFormat - end - - if not self.EscortMenuFlare then - self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, { ParamSelf = self } ) - self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Green, ParamMessage = "Released a green flare!" } ) - self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Red, ParamMessage = "Released a red flare!" } ) - self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.White, ParamMessage = "Released a white flare!" } ) - self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Yellow, ParamMessage = "Released a yellow flare!" } ) - end - - return self -end - ---- Defines a menu slot to let the escort disperse a smoke in a certain color. --- This menu will appear under **Navigation**. --- Note that smoke menu options will only be displayed for ships and ground units. Not for air units. --- The smoke will be fired from the first unit in the group. --- @param #ESCORT self --- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuSmoke( MenuTextFormat ) - self:F() - - if not self.EscortGroup:IsAir() then - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Smoke" - else - MenuText = MenuTextFormat - end - - if not self.EscortMenuSmoke then - self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, { ParamSelf = self } ) - self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Green, ParamMessage = "Releasing green smoke!" } ) - self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Red, ParamMessage = "Releasing red smoke!" } ) - self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.White, ParamMessage = "Releasing white smoke!" } ) - self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Orange, ParamMessage = "Releasing orange smoke!" } ) - self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Blue, ParamMessage = "Releasing blue smoke!" } ) - end - end - - return self -end - ---- Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds. --- This menu will appear under **Report targets**. --- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. --- @param #ESCORT self --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. --- @return #ESCORT -function ESCORT:MenuReportTargets( Seconds ) - self:F( { Seconds } ) - - if not self.EscortMenuReportNearbyTargets then - self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) - end - - if not Seconds then - Seconds = 30 - end - - -- Report Targets - self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, { ParamSelf = self } ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) - - -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - - - self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) - - return self -end - ---- Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client. --- This menu will appear under **Request assistance from**. --- Note that this method needs to be preceded with the method MenuReportTargets. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuAssistedAttack() - self:F() - - -- Request assistance from other escorts. - -- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane... - self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu ) - - return self -end - ---- Defines a menu to let the escort set its rules of engagement. --- All rules of engagement will appear under the menu **ROE**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuROE( MenuTextFormat ) - self:F( MenuTextFormat ) - - if not self.EscortMenuROE then - -- Rules of Engagement - self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) - if self.EscortGroup:OptionROEHoldFirePossible() then - self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEHoldFire(), ParamMessage = "Holding weapons!" } ) - end - if self.EscortGroup:OptionROEReturnFirePossible() then - self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEReturnFire(), ParamMessage = "Returning fire!" } ) - end - if self.EscortGroup:OptionROEOpenFirePossible() then - self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEOpenFire(), ParamMessage = "Opening fire on designated targets!!" } ) - end - if self.EscortGroup:OptionROEWeaponFreePossible() then - self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEWeaponFree(), ParamMessage = "Opening fire on targets of opportunity!" } ) - end - end - - return self -end - - ---- Defines a menu to let the escort set its evasion when under threat. --- All rules of engagement will appear under the menu **Evasion**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuEvasion( MenuTextFormat ) - self:F( MenuTextFormat ) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuEvasion then - -- Reaction to Threats - self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) - if self.EscortGroup:OptionROTNoReactionPossible() then - self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTNoReaction(), ParamMessage = "Fighting until death!" } ) - end - if self.EscortGroup:OptionROTPassiveDefensePossible() then - self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTPassiveDefense(), ParamMessage = "Defending using jammers, chaff and flares!" } ) - end - if self.EscortGroup:OptionROTEvadeFirePossible() then - self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTEvadeFire(), ParamMessage = "Evading on enemy fire!" } ) - end - if self.EscortGroup:OptionROTVerticalPossible() then - self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } ) - end - end - end - - return self -end - ---- Defines a menu to let the escort resume its mission from a waypoint on its route. --- All rules of engagement will appear under the menu **Resume mission from**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuResumeMission() - self:F() - - if not self.EscortMenuResumeMission then - -- Mission Resume Menu Root - self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu ) - end - - return self -end - - ---- @param #MENUPARAM MenuParam -function ESCORT._HoldPosition( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local OrbitGroup = MenuParam.ParamOrbitGroup -- Wrapper.Group#GROUP - local OrbitUnit = OrbitGroup:GetUnit(1) -- Wrapper.Unit#UNIT - local OrbitHeight = MenuParam.ParamHeight - local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet - - self.FollowScheduler:Stop() - - local PointFrom = {} - local GroupVec3 = EscortGroup:GetUnit(1):GetVec3() - PointFrom = {} - PointFrom.x = GroupVec3.x - PointFrom.y = GroupVec3.z - PointFrom.speed = 250 - PointFrom.type = AI.Task.WaypointType.TURNING_POINT - PointFrom.alt = GroupVec3.y - PointFrom.alt_type = AI.Task.AltitudeType.BARO - - local OrbitPoint = OrbitUnit:GetVec2() - local PointTo = {} - PointTo.x = OrbitPoint.x - PointTo.y = OrbitPoint.y - PointTo.speed = 250 - PointTo.type = AI.Task.WaypointType.TURNING_POINT - PointTo.alt = OrbitHeight - PointTo.alt_type = AI.Task.AltitudeType.BARO - PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( OrbitPoint, OrbitHeight, 0 ) - - local Points = { PointFrom, PointTo } - - EscortGroup:OptionROEHoldFire() - EscortGroup:OptionROTPassiveDefense() - - EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) ) - EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._JoinUpAndFollow( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self.Distance = MenuParam.ParamDistance - - self:JoinUpAndFollow( EscortGroup, EscortClient, self.Distance ) -end - ---- JoinsUp and Follows a CLIENT. --- @param Functional.Escort#ESCORT self --- @param Wrapper.Group#GROUP EscortGroup --- @param Wrapper.Client#CLIENT EscortClient --- @param Dcs.DCSTypes#Distance Distance -function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) - self:F( { EscortGroup, EscortClient, Distance } ) - - self.FollowScheduler:Stop() - - EscortGroup:OptionROEHoldFire() - EscortGroup:OptionROTPassiveDefense() - - self.EscortMode = ESCORT.MODE.FOLLOW - - self.CT1 = 0 - self.GT1 = 0 - self.FollowScheduler:Start() - - EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._Flare( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local Color = MenuParam.ParamColor - local Message = MenuParam.ParamMessage - - EscortGroup:GetUnit(1):Flare( Color ) - EscortGroup:MessageToClient( Message, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._Smoke( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local Color = MenuParam.ParamColor - local Message = MenuParam.ParamMessage - - EscortGroup:GetUnit(1):Smoke( Color ) - EscortGroup:MessageToClient( Message, 10, EscortClient ) -end - - ---- @param #MENUPARAM MenuParam -function ESCORT._ReportNearbyTargetsNow( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self:_ReportTargetsScheduler() - -end - -function ESCORT._SwitchReportNearbyTargets( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self.ReportTargets = MenuParam.ParamReportTargets - - if self.ReportTargets then - if not self.ReportTargetsScheduler then - self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, 30 ) - end - else - routines.removeFunction( self.ReportTargetsScheduler ) - self.ReportTargetsScheduler = nil - end -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ScanTargets( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local ScanDuration = MenuParam.ParamScanDuration - - self.FollowScheduler:Stop() - - if EscortGroup:IsHelicopter() then - SCHEDULER:New( EscortGroup, EscortGroup.PushTask, - { EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 200, 20 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - 1 - ) - elseif EscortGroup:IsAirPlane() then - SCHEDULER:New( EscortGroup, EscortGroup.PushTask, - { EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 1000, 500 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - 1 - ) - end - - EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient ) - - if self.EscortMode == ESCORT.MODE.FOLLOW then - self.FollowScheduler:Start() - end - -end - ---- @param Wrapper.Group#GROUP EscortGroup -function _Resume( EscortGroup ) - env.info( '_Resume' ) - - local Escort = EscortGroup:GetState( EscortGroup, "Escort" ) - env.info( "EscortMode = " .. Escort.EscortMode ) - if Escort.EscortMode == ESCORT.MODE.FOLLOW then - Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance ) - end - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._AttackTarget( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - - local EscortClient = self.EscortClient - local AttackUnit = MenuParam.ParamUnit -- Wrapper.Unit#UNIT - - self.FollowScheduler:Stop() - - self:T( AttackUnit ) - - if EscortGroup:IsAir() then - EscortGroup:OptionROEOpenFire() - EscortGroup:OptionROTPassiveDefense() - EscortGroup:SetState( EscortGroup, "Escort", self ) - SCHEDULER:New( EscortGroup, - EscortGroup.PushTask, - { EscortGroup:TaskCombo( - { EscortGroup:TaskAttackUnit( AttackUnit ), - EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } ) - } - ) - }, 10 - ) - else - SCHEDULER:New( EscortGroup, - EscortGroup.PushTask, - { EscortGroup:TaskCombo( - { EscortGroup:TaskFireAtPoint( AttackUnit:GetVec2(), 50 ) - } - ) - }, 10 - ) - end - - EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._AssistTarget( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - local EscortGroupAttack = MenuParam.ParamEscortGroup - local AttackUnit = MenuParam.ParamUnit -- Wrapper.Unit#UNIT - - self.FollowScheduler:Stop() - - self:T( AttackUnit ) - - if EscortGroupAttack:IsAir() then - EscortGroupAttack:OptionROEOpenFire() - EscortGroupAttack:OptionROTVertical() - SCHDULER:New( EscortGroupAttack, - EscortGroupAttack.PushTask, - { EscortGroupAttack:TaskCombo( - { EscortGroupAttack:TaskAttackUnit( AttackUnit ), - EscortGroupAttack:TaskOrbitCircle( 500, 350 ) - } - ) - }, 10 - ) - else - SCHEDULER:New( EscortGroupAttack, - EscortGroupAttack.PushTask, - { EscortGroupAttack:TaskCombo( - { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetVec2(), 50 ) - } - ) - }, 10 - ) - end - EscortGroupAttack:MessageToClient( "Assisting with the destroying the enemy unit!", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ROE( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local EscortROEFunction = MenuParam.ParamFunction - local EscortROEMessage = MenuParam.ParamMessage - - pcall( function() EscortROEFunction() end ) - EscortGroup:MessageToClient( EscortROEMessage, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ROT( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local EscortROTFunction = MenuParam.ParamFunction - local EscortROTMessage = MenuParam.ParamMessage - - pcall( function() EscortROTFunction() end ) - EscortGroup:MessageToClient( EscortROTMessage, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ResumeMission( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local WayPoint = MenuParam.ParamWayPoint - - self.FollowScheduler:Stop() - - local WayPoints = EscortGroup:GetTaskRoute() - self:T( WayPoint, WayPoints ) - - for WayPointIgnore = 1, WayPoint do - table.remove( WayPoints, 1 ) - end - - SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) - - EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) -end - ---- Registers the waypoints --- @param #ESCORT self --- @return #table -function ESCORT:RegisterRoute() - self:F() - - local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP - - local TaskPoints = EscortGroup:GetTaskRoute() - - self:T( TaskPoints ) - - return TaskPoints -end - ---- @param Functional.Escort#ESCORT self -function ESCORT:_FollowScheduler() - self:F( { self.FollowDistance } ) - - self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } ) - if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then - - local ClientUnit = self.EscortClient:GetClientGroupUnit() - local GroupUnit = self.EscortGroup:GetUnit( 1 ) - local FollowDistance = self.FollowDistance - - self:T( {ClientUnit.UnitName, GroupUnit.UnitName } ) - - if self.CT1 == 0 and self.GT1 == 0 then - self.CV1 = ClientUnit:GetVec3() - self:T( { "self.CV1", self.CV1 } ) - self.CT1 = timer.getTime() - self.GV1 = GroupUnit:GetVec3() - self.GT1 = timer.getTime() - else - local CT1 = self.CT1 - local CT2 = timer.getTime() - local CV1 = self.CV1 - local CV2 = ClientUnit:GetVec3() - self.CT1 = CT2 - self.CV1 = CV2 - - local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 - local CT = CT2 - CT1 - - local CS = ( 3600 / CT ) * ( CD / 1000 ) - - self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) - - local GT1 = self.GT1 - local GT2 = timer.getTime() - local GV1 = self.GV1 - local GV2 = GroupUnit:GetVec3() - self.GT1 = GT2 - self.GV1 = GV2 - - local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 - local GT = GT2 - GT1 - - local GS = ( 3600 / GT ) * ( GD / 1000 ) - - self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) - - -- Calculate the group direction vector - local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } - - -- Calculate GH2, GH2 with the same height as CV2. - local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } - - -- Calculate the angle of GV to the orthonormal plane - local alpha = math.atan2( GV.z, GV.x ) - - -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. - -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) - local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), - y = GH2.y, - z = CV2.z + FollowDistance * math.sin(alpha), - } - - -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. - local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } - - -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. - -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. - -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... - local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } - - -- Now we can calculate the group destination vector GDV. - local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } - - if self.SmokeDirectionVector == true then - trigger.action.smoke( GDV, trigger.smokeColor.Red ) - end - - self:T2( { "CV2:", CV2 } ) - self:T2( { "CVI:", CVI } ) - self:T2( { "GDV:", GDV } ) - - -- Measure distance between client and group - local CatchUpDistance = ( ( GDV.x - GV2.x )^2 + ( GDV.y - GV2.y )^2 + ( GDV.z - GV2.z )^2 ) ^ 0.5 - - -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome - -- the requested Distance). - local Time = 10 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 8.4 ) ) / Time - - local Speed = CS + CatchUpSpeed - if Speed < 0 then - Speed = 0 - end - - self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } ) - - -- Now route the escort to the desired point with the desired speed. - self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) - end - - return true - end - - return false -end - - ---- Report Targets Scheduler. --- @param #ESCORT self -function ESCORT:_ReportTargetsScheduler() - self:F( self.EscortGroup:GetName() ) - - if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then - local EscortGroupName = self.EscortGroup:GetName() - local EscortTargets = self.EscortGroup:GetDetectedTargets() - - local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets - - local EscortTargetMessages = "" - for EscortTargetID, EscortTarget in pairs( EscortTargets ) do - local EscortObject = EscortTarget.object - self:T( EscortObject ) - if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then - - local EscortTargetUnit = UNIT:Find( EscortObject ) - local EscortTargetUnitName = EscortTargetUnit:GetName() - - - - -- local EscortTargetIsDetected, - -- EscortTargetIsVisible, - -- EscortTargetLastTime, - -- EscortTargetKnowType, - -- EscortTargetKnowDistance, - -- EscortTargetLastPos, - -- EscortTargetLastVelocity - -- = self.EscortGroup:IsTargetDetected( EscortObject ) - -- - -- self:T( { EscortTargetIsDetected, - -- EscortTargetIsVisible, - -- EscortTargetLastTime, - -- EscortTargetKnowType, - -- EscortTargetKnowDistance, - -- EscortTargetLastPos, - -- EscortTargetLastVelocity } ) - - - local EscortTargetUnitVec3 = EscortTargetUnit:GetVec3() - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + - ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + - ( EscortTargetUnitVec3.z - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } ) - - if Distance <= 15 then - - if not ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = {} - end - ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit - ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible - ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type - ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance - else - if ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = nil - end - end - end - end - - self:T( { "Sorting Targets Table:", ClientEscortTargets } ) - table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end ) - self:T( { "Sorted Targets Table:", ClientEscortTargets } ) - - -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup. - self.EscortMenuAttackNearbyTargets:RemoveSubMenus() - - if self.EscortMenuTargetAssistance then - self.EscortMenuTargetAssistance:RemoveSubMenus() - end - - --for MenuIndex = 1, #self.EscortMenuAttackTargets do - -- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) - -- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() - --end - - - if ClientEscortTargets then - for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do - - for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do - - if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then - - local EscortTargetMessage = "" - local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName() - local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName() - if ClientEscortTargetData.type then - EscortTargetMessage = EscortTargetMessage .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at " - else - EscortTargetMessage = EscortTargetMessage .. "Unknown target at " - end - - local EscortTargetUnitVec3 = ClientEscortTargetData.AttackUnit:GetVec3() - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + - ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + - ( EscortTargetUnitVec3.z - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } ) - if ClientEscortTargetData.visible == false then - EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km" - else - EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" - end - - if ClientEscortTargetData.visible then - EscortTargetMessage = EscortTargetMessage .. ", visual" - end - - if ClientEscortGroupName == EscortGroupName then - - MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - self.EscortMenuAttackNearbyTargets, - ESCORT._AttackTarget, - { ParamSelf = self, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) - EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage - else - if self.EscortMenuTargetAssistance then - local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) - MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - MenuTargetAssistance, - ESCORT._AssistTarget, - { ParamSelf = self, - ParamEscortGroup = EscortGroupData.EscortGroup, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) - end - end - else - ClientEscortTargetData = nil - end - end - end - - if EscortTargetMessages ~= "" and self.ReportTargets == true then - self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient ) - else - self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient ) - end - end - - if self.EscortMenuResumeMission then - self.EscortMenuResumeMission:RemoveSubMenus() - - -- if self.EscortMenuResumeWayPoints then - -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do - -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } ) - -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove() - -- end - -- end - - local TaskPoints = self:RegisterRoute() - for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + - ( WayPoint.y - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) - end - end - - return true - end - - return false -end ---- This module contains the MISSILETRAINER class. --- --- === --- --- 1) @{Functional.MissileTrainer#MISSILETRAINER} class, extends @{Core.Base#BASE} --- =============================================================== --- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft, --- the class will destroy the missile within a certain range, to avoid damage to your aircraft. --- It suports the following functionality: --- --- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes. --- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range � --- * Provide alerts when a missile would have killed your aircraft. --- * Provide alerts when the missile self destructs. --- * Enable / Disable and Configure the Missile Trainer using the various menu options. --- --- When running a mission where MISSILETRAINER is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players: --- --- * **Messages**: Menu to configure all messages. --- * **Messages On**: Show all messages. --- * **Messages Off**: Disable all messages. --- * **Tracking**: Menu to configure missile tracking messages. --- * **To All**: Shows missile tracking messages to all players. --- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at. --- * **Tracking On**: Show missile tracking messages. --- * **Tracking Off**: Disable missile tracking messages. --- * **Frequency Increase**: Increases the missile tracking message frequency with one second. --- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second. --- * **Alerts**: Menu to configure alert messages. --- * **To All**: Shows alert messages to all players. --- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at. --- * **Hits On**: Show missile hit alert messages. --- * **Hits Off**: Disable missile hit alert messages. --- * **Launches On**: Show missile launch messages. --- * **Launches Off**: Disable missile launch messages. --- * **Details**: Menu to configure message details. --- * **Range On**: Shows range information when a missile is fired to a target. --- * **Range Off**: Disable range information when a missile is fired to a target. --- * **Bearing On**: Shows bearing information when a missile is fired to a target. --- * **Bearing Off**: Disable bearing information when a missile is fired to a target. --- * **Distance**: Menu to configure the distance when a missile needs to be destroyed when near to a player, during tracking. This will improve/influence hit calculation accuracy, but has the risk of damaging the aircraft when the missile reaches the aircraft before the distance is measured. --- * **50 meter**: Destroys the missile when the distance to the aircraft is below or equal to 50 meter. --- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter. --- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter. --- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter. --- --- --- 1.1) MISSILETRAINER construction methods: --- ----------------------------------------- --- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method: --- --- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed. --- --- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those. --- --- 1.2) MISSILETRAINER initialization methods: --- ------------------------------------------- --- A MISSILETRAINER object will behave differently based on the usage of initialization methods: --- --- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF. --- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you. --- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF. --- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. --- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you. --- * @{#MISSILETRAINER.InitAlertsHitsOnOff}: Sets by default the display of hit alerts ON or OFF. --- * @{#MISSILETRAINER.InitAlertsLaunchesOnOff}: Sets by default the display of launch alerts ON or OFF. --- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF. --- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF. --- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu. --- --- === --- --- CREDITS --- ======= --- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums. --- Working together with Danny has resulted in the MISSILETRAINER class. --- Danny has shared his ideas and together we made a design. --- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback! --- --- @module MissileTrainer --- @author FlightControl - - ---- The MISSILETRAINER class --- @type MISSILETRAINER --- @field Core.Set#SET_CLIENT DBClients --- @extends Core.Base#BASE -MISSILETRAINER = { - ClassName = "MISSILETRAINER", - TrackingMissiles = {}, -} - -function MISSILETRAINER._Alive( Client, self ) - - if self.Briefing then - Client:Message( self.Briefing, 15, "Trainer" ) - end - - if self.MenusOnOff == true then - Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" ) - - Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT - - Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu ) - Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } ) - Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } ) - - Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu ) - Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } ) - Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } ) - Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } ) - Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } ) - Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } ) - Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } ) - - Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu ) - Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } ) - Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } ) - Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } ) - Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } ) - Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } ) - Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } ) - - Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu ) - Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } ) - Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } ) - Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } ) - Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } ) - - Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu ) - Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } ) - Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } ) - Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } ) - Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } ) - else - if Client.MainMenu then - Client.MainMenu:Remove() - end - end - - local ClientID = Client:GetID() - self:T( ClientID ) - if not self.TrackingMissiles[ClientID] then - self.TrackingMissiles[ClientID] = {} - end - self.TrackingMissiles[ClientID].Client = Client - if not self.TrackingMissiles[ClientID].MissileData then - self.TrackingMissiles[ClientID].MissileData = {} - end -end - ---- Creates the main object which is handling missile tracking. --- When a missile is fired a SCHEDULER is set off that follows the missile. When near a certain a client player, the missile will be destroyed. --- @param #MISSILETRAINER self --- @param #number Distance The distance in meters when a tracked missile needs to be destroyed when close to a player. --- @param #string Briefing (Optional) Will show a text to the players when starting their mission. Can be used for briefing purposes. --- @return #MISSILETRAINER -function MISSILETRAINER:New( Distance, Briefing ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( Distance ) - - if Briefing then - self.Briefing = Briefing - end - - self.Schedulers = {} - self.SchedulerID = 0 - - self.MessageInterval = 2 - self.MessageLastTime = timer.getTime() - - self.Distance = Distance / 1000 - - _EVENTDISPATCHER:OnShot( self._EventShot, self ) - - self.DBClients = SET_CLIENT:New():FilterStart() - - --- for ClientID, Client in pairs( self.DBClients.Database ) do --- self:E( "ForEach:" .. Client.UnitName ) --- Client:Alive( self._Alive, self ) --- end --- - self.DBClients:ForEachClient( - function( Client ) - self:E( "ForEach:" .. Client.UnitName ) - Client:Alive( self._Alive, self ) - end - ) - - - --- self.DB:ForEachClient( --- --- @param Wrapper.Client#CLIENT Client --- function( Client ) --- --- ... actions ... --- --- end --- ) - - self.MessagesOnOff = true - - self.TrackingToAll = false - self.TrackingOnOff = true - self.TrackingFrequency = 3 - - self.AlertsToAll = true - self.AlertsHitsOnOff = true - self.AlertsLaunchesOnOff = true - - self.DetailsRangeOnOff = true - self.DetailsBearingOnOff = true - - self.MenusOnOff = true - - self.TrackingMissiles = {} - - self.TrackingScheduler = SCHEDULER:New( self, self._TrackMissiles, {}, 0.5, 0.05, 0 ) - - return self -end - --- Initialization methods. - - - ---- Sets by default the display of any message to be ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean MessagesOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff ) - self:F( MessagesOnOff ) - - self.MessagesOnOff = MessagesOnOff - if self.MessagesOnOff == true then - MESSAGE:New( "Messages ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Messages OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the missile tracking report for all players or only for those missiles targetted to you. --- @param #MISSILETRAINER self --- @param #boolean TrackingToAll true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingToAll( TrackingToAll ) - self:F( TrackingToAll ) - - self.TrackingToAll = TrackingToAll - if self.TrackingToAll == true then - MESSAGE:New( "Missile tracking to all players ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Missile tracking to all players OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of missile tracking report to be ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean TrackingOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingOnOff( TrackingOnOff ) - self:F( TrackingOnOff ) - - self.TrackingOnOff = TrackingOnOff - if self.TrackingOnOff == true then - MESSAGE:New( "Missile tracking ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Missile tracking OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. --- The default frequency is a 3 second interval, so the Tracking Frequency parameter specifies the increase or decrease from the default 3 seconds or the last frequency update. --- @param #MISSILETRAINER self --- @param #number TrackingFrequency Provide a negative or positive value in seconds to incraese or decrease the display frequency. --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingFrequency( TrackingFrequency ) - self:F( TrackingFrequency ) - - self.TrackingFrequency = self.TrackingFrequency + TrackingFrequency - if self.TrackingFrequency < 0.5 then - self.TrackingFrequency = 0.5 - end - if self.TrackingFrequency then - MESSAGE:New( "Missile tracking frequency is " .. self.TrackingFrequency .. " seconds.", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of alerts to be shown to all players or only to you. --- @param #MISSILETRAINER self --- @param #boolean AlertsToAll true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsToAll( AlertsToAll ) - self:F( AlertsToAll ) - - self.AlertsToAll = AlertsToAll - if self.AlertsToAll == true then - MESSAGE:New( "Alerts to all players ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts to all players OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of hit alerts ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean AlertsHitsOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsHitsOnOff( AlertsHitsOnOff ) - self:F( AlertsHitsOnOff ) - - self.AlertsHitsOnOff = AlertsHitsOnOff - if self.AlertsHitsOnOff == true then - MESSAGE:New( "Alerts Hits ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts Hits OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of launch alerts ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean AlertsLaunchesOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsLaunchesOnOff( AlertsLaunchesOnOff ) - self:F( AlertsLaunchesOnOff ) - - self.AlertsLaunchesOnOff = AlertsLaunchesOnOff - if self.AlertsLaunchesOnOff == true then - MESSAGE:New( "Alerts Launches ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts Launches OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of range information of missiles ON of OFF. --- @param #MISSILETRAINER self --- @param #boolean DetailsRangeOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitRangeOnOff( DetailsRangeOnOff ) - self:F( DetailsRangeOnOff ) - - self.DetailsRangeOnOff = DetailsRangeOnOff - if self.DetailsRangeOnOff == true then - MESSAGE:New( "Range display ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Range display OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of bearing information of missiles ON of OFF. --- @param #MISSILETRAINER self --- @param #boolean DetailsBearingOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitBearingOnOff( DetailsBearingOnOff ) - self:F( DetailsBearingOnOff ) - - self.DetailsBearingOnOff = DetailsBearingOnOff - if self.DetailsBearingOnOff == true then - MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Enables / Disables the menus. --- @param #MISSILETRAINER self --- @param #boolean MenusOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitMenusOnOff( MenusOnOff ) - self:F( MenusOnOff ) - - self.MenusOnOff = MenusOnOff - if self.MenusOnOff == true then - MESSAGE:New( "Menus are ENABLED (only when a player rejoins a slot)", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Menus are DISABLED", 15, "Menu" ):ToAll() - end - - return self -end - - --- Menu functions - -function MISSILETRAINER._MenuMessages( MenuParameters ) - - local self = MenuParameters.MenuSelf - - if MenuParameters.MessagesOnOff ~= nil then - self:InitMessagesOnOff( MenuParameters.MessagesOnOff ) - end - - if MenuParameters.TrackingToAll ~= nil then - self:InitTrackingToAll( MenuParameters.TrackingToAll ) - end - - if MenuParameters.TrackingOnOff ~= nil then - self:InitTrackingOnOff( MenuParameters.TrackingOnOff ) - end - - if MenuParameters.TrackingFrequency ~= nil then - self:InitTrackingFrequency( MenuParameters.TrackingFrequency ) - end - - if MenuParameters.AlertsToAll ~= nil then - self:InitAlertsToAll( MenuParameters.AlertsToAll ) - end - - if MenuParameters.AlertsHitsOnOff ~= nil then - self:InitAlertsHitsOnOff( MenuParameters.AlertsHitsOnOff ) - end - - if MenuParameters.AlertsLaunchesOnOff ~= nil then - self:InitAlertsLaunchesOnOff( MenuParameters.AlertsLaunchesOnOff ) - end - - if MenuParameters.DetailsRangeOnOff ~= nil then - self:InitRangeOnOff( MenuParameters.DetailsRangeOnOff ) - end - - if MenuParameters.DetailsBearingOnOff ~= nil then - self:InitBearingOnOff( MenuParameters.DetailsBearingOnOff ) - end - - if MenuParameters.Distance ~= nil then - self.Distance = MenuParameters.Distance - MESSAGE:New( "Hit detection distance set to " .. self.Distance .. " meters", 15, "Menu" ):ToAll() - end - -end - ---- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. --- @param #MISSILETRAINER self --- @param Core.Event#EVENTDATA Event -function MISSILETRAINER:_EventShot( Event ) - self:F( { Event } ) - - local TrainerSourceDCSUnit = Event.IniDCSUnit - local TrainerSourceDCSUnitName = Event.IniDCSUnitName - local TrainerWeapon = Event.Weapon -- Identify the weapon fired - local TrainerWeaponName = Event.WeaponName -- return weapon type - - self:T( "Missile Launched = " .. TrainerWeaponName ) - - local TrainerTargetDCSUnit = TrainerWeapon:getTarget() -- Identify target - if TrainerTargetDCSUnit then - local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit ) - local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill - - self:T(TrainerTargetDCSUnitName ) - - local Client = self.DBClients:FindClient( TrainerTargetDCSUnitName ) - if Client then - - local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit ) - local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit ) - - if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then - - local Message = MESSAGE:New( - string.format( "%s launched a %s", - TrainerSourceUnit:GetTypeName(), - TrainerWeaponName - ) .. self:_AddRange( Client, TrainerWeapon ) .. self:_AddBearing( Client, TrainerWeapon ), 5, "Launch Alert" ) - - if self.AlertsToAll then - Message:ToAll() - else - Message:ToClient( Client ) - end - end - - local ClientID = Client:GetID() - self:T( ClientID ) - local MissileData = {} - MissileData.TrainerSourceUnit = TrainerSourceUnit - MissileData.TrainerWeapon = TrainerWeapon - MissileData.TrainerTargetUnit = TrainerTargetUnit - MissileData.TrainerWeaponTypeName = TrainerWeapon:getTypeName() - MissileData.TrainerWeaponLaunched = true - table.insert( self.TrackingMissiles[ClientID].MissileData, MissileData ) - --self:T( self.TrackingMissiles ) - end - else - -- TODO: some weapons don't know the target unit... Need to develop a workaround for this. - SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) - if ( TrainerWeapon:getTypeName() == "9M311" ) then - SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) - else - end - end -end - -function MISSILETRAINER:_AddRange( Client, TrainerWeapon ) - - local RangeText = "" - - if self.DetailsRangeOnOff then - - local PositionMissile = TrainerWeapon:getPoint() - local TargetVec3 = Client:GetVec3() - - local Range = ( ( PositionMissile.x - TargetVec3.x )^2 + - ( PositionMissile.y - TargetVec3.y )^2 + - ( PositionMissile.z - TargetVec3.z )^2 - ) ^ 0.5 / 1000 - - RangeText = string.format( ", at %4.2fkm", Range ) - end - - return RangeText -end - -function MISSILETRAINER:_AddBearing( Client, TrainerWeapon ) - - local BearingText = "" - - if self.DetailsBearingOnOff then - - local PositionMissile = TrainerWeapon:getPoint() - local TargetVec3 = Client:GetVec3() - - self:T2( { TargetVec3, PositionMissile }) - - local DirectionVector = { x = PositionMissile.x - TargetVec3.x, y = PositionMissile.y - TargetVec3.y, z = PositionMissile.z - TargetVec3.z } - local DirectionRadians = math.atan2( DirectionVector.z, DirectionVector.x ) - --DirectionRadians = DirectionRadians + routines.getNorthCorrection( PositionTarget ) - if DirectionRadians < 0 then - DirectionRadians = DirectionRadians + 2 * math.pi - end - local DirectionDegrees = DirectionRadians * 180 / math.pi - - BearingText = string.format( ", %d degrees", DirectionDegrees ) - end - - return BearingText -end - - -function MISSILETRAINER:_TrackMissiles() - self:F2() - - - local ShowMessages = false - if self.MessagesOnOff and self.MessageLastTime + self.TrackingFrequency <= timer.getTime() then - self.MessageLastTime = timer.getTime() - ShowMessages = true - end - - -- ALERTS PART - - -- Loop for all Player Clients to check the alerts and deletion of missiles. - for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do - - local Client = ClientData.Client - self:T2( { Client:GetName() } ) - - for MissileDataID, MissileData in pairs( ClientData.MissileData ) do - self:T3( MissileDataID ) - - local TrainerSourceUnit = MissileData.TrainerSourceUnit - local TrainerWeapon = MissileData.TrainerWeapon - local TrainerTargetUnit = MissileData.TrainerTargetUnit - local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName - local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched - - if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then - local PositionMissile = TrainerWeapon:getPosition().p - local TargetVec3 = Client:GetVec3() - - local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 + - ( PositionMissile.y - TargetVec3.y )^2 + - ( PositionMissile.z - TargetVec3.z )^2 - ) ^ 0.5 / 1000 - - if Distance <= self.Distance then - -- Hit alert - TrainerWeapon:destroy() - if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then - - self:T( "killed" ) - - local Message = MESSAGE:New( - string.format( "%s launched by %s killed %s", - TrainerWeapon:getTypeName(), - TrainerSourceUnit:GetTypeName(), - TrainerTargetUnit:GetPlayerName() - ), 15, "Hit Alert" ) - - if self.AlertsToAll == true then - Message:ToAll() - else - Message:ToClient( Client ) - end - - MissileData = nil - table.remove( ClientData.MissileData, MissileDataID ) - self:T(ClientData.MissileData) - end - end - else - if not ( TrainerWeapon and TrainerWeapon:isExist() ) then - if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then - -- Weapon does not exist anymore. Delete from Table - local Message = MESSAGE:New( - string.format( "%s launched by %s self destructed!", - TrainerWeaponTypeName, - TrainerSourceUnit:GetTypeName() - ), 5, "Tracking" ) - - if self.AlertsToAll == true then - Message:ToAll() - else - Message:ToClient( Client ) - end - end - MissileData = nil - table.remove( ClientData.MissileData, MissileDataID ) - self:T( ClientData.MissileData ) - end - end - end - end - - if ShowMessages == true and self.MessagesOnOff == true and self.TrackingOnOff == true then -- Only do this when tracking information needs to be displayed. - - -- TRACKING PART - - -- For the current client, the missile range and bearing details are displayed To the Player Client. - -- For the other clients, the missile range and bearing details are displayed To the other Player Clients. - -- To achieve this, a cross loop is done for each Player Client <-> Other Player Client missile information. - - -- Main Player Client loop - for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do - - local Client = ClientData.Client - self:T2( { Client:GetName() } ) - - - ClientData.MessageToClient = "" - ClientData.MessageToAll = "" - - -- Other Players Client loop - for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do - - for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do - self:T3( MissileDataID ) - - local TrainerSourceUnit = MissileData.TrainerSourceUnit - local TrainerWeapon = MissileData.TrainerWeapon - local TrainerTargetUnit = MissileData.TrainerTargetUnit - local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName - local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched - - if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then - - if ShowMessages == true then - local TrackingTo - TrackingTo = string.format( " -> %s", - TrainerWeaponTypeName - ) - - if ClientDataID == TrackingDataID then - if ClientData.MessageToClient == "" then - ClientData.MessageToClient = "Missiles to You:\n" - end - ClientData.MessageToClient = ClientData.MessageToClient .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. "\n" - else - if self.TrackingToAll == true then - if ClientData.MessageToAll == "" then - ClientData.MessageToAll = "Missiles to other Players:\n" - end - ClientData.MessageToAll = ClientData.MessageToAll .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. " ( " .. TrainerTargetUnit:GetPlayerName() .. " )\n" - end - end - end - end - end - end - - -- Once the Player Client and the Other Player Client tracking messages are prepared, show them. - if ClientData.MessageToClient ~= "" or ClientData.MessageToAll ~= "" then - local Message = MESSAGE:New( ClientData.MessageToClient .. ClientData.MessageToAll, 1, "Tracking" ):ToClient( Client ) - end - end - end - - return true -end ---- This module contains the AIRBASEPOLICE classes. --- --- === --- --- 1) @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} class, extends @{Core.Base#BASE} --- ================================================================== --- The @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} class provides the main methods to monitor CLIENT behaviour at airbases. --- CLIENTS should not be allowed to: --- --- * Don't taxi faster than 40 km/h. --- * Don't take-off on taxiways. --- * Avoid to hit other planes on the airbase. --- * Obey ground control orders. --- --- 2) @{Functional.AirbasePolice#AIRBASEPOLICE_CAUCASUS} class, extends @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} --- ============================================================================================= --- All the airbases on the caucasus map can be monitored using this class. --- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. --- The following names can be given: --- * AnapaVityazevo --- * Batumi --- * Beslan --- * Gelendzhik --- * Gudauta --- * Kobuleti --- * KrasnodarCenter --- * KrasnodarPashkovsky --- * Krymsk --- * Kutaisi --- * MaykopKhanskaya --- * MineralnyeVody --- * Mozdok --- * Nalchik --- * Novorossiysk --- * SenakiKolkhi --- * SochiAdler --- * Soganlug --- * SukhumiBabushara --- * TbilisiLochini --- * Vaziani --- --- 3) @{Functional.AirbasePolice#AIRBASEPOLICE_NEVADA} class, extends @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} --- ============================================================================================= --- All the airbases on the NEVADA map can be monitored using this class. --- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. --- The following names can be given: --- * Nellis --- * McCarran --- * Creech --- * Groom Lake --- --- ### Contributions: Dutch Baron - Concept & Testing --- ### Author: FlightControl - Framework Design & Programming --- --- @module AirbasePolice - - - - - ---- @type AIRBASEPOLICE_BASE --- @field Core.Set#SET_CLIENT SetClient --- @extends Core.Base#BASE - -AIRBASEPOLICE_BASE = { - ClassName = "AIRBASEPOLICE_BASE", - SetClient = nil, - Airbases = nil, - AirbaseNames = nil, -} - - ---- Creates a new AIRBASEPOLICE_BASE object. --- @param #AIRBASEPOLICE_BASE self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @param Airbases A table of Airbase Names. --- @return #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:New( SetClient, Airbases ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - self:E( { self.ClassName, SetClient, Airbases } ) - - self.SetClient = SetClient - self.Airbases = Airbases - - for AirbaseID, Airbase in pairs( self.Airbases ) do - Airbase.ZoneBoundary = ZONE_POLYGON_BASE:New( "Boundary", Airbase.PointsBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - for PointsRunwayID, PointsRunway in pairs( Airbase.PointsRunways ) do - Airbase.ZoneRunways[PointsRunwayID] = ZONE_POLYGON_BASE:New( "Runway " .. PointsRunwayID, PointsRunway ):SmokeZone(SMOKECOLOR.Red):Flush() - end - end - --- -- Template --- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) --- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) --- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - - self.SetClient:ForEachClient( - --- @param Wrapper.Client#CLIENT Client - function( Client ) - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0) - Client:SetState( self, "Taxi", false ) - end - ) - - self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, {}, 0, 2, 0.05 ) - - return self -end - ---- @type AIRBASEPOLICE_BASE.AirbaseNames --- @list <#string> - ---- Monitor a table of airbase names. --- @param #AIRBASEPOLICE_BASE self --- @param #AIRBASEPOLICE_BASE.AirbaseNames AirbaseNames A list of AirbaseNames to monitor. If this parameters is nil, then all airbases will be monitored. --- @return #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:Monitor( AirbaseNames ) - - if AirbaseNames then - if type( AirbaseNames ) == "table" then - self.AirbaseNames = AirbaseNames - else - self.AirbaseNames = { AirbaseNames } - end - end -end - ---- @param #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:_AirbaseMonitor() - - for AirbaseID, Airbase in pairs( self.Airbases ) do - - if not self.AirbaseNames or self.AirbaseNames[AirbaseID] then - - self:E( AirbaseID ) - - self.SetClient:ForEachClientInZone( Airbase.ZoneBoundary, - - --- @param Wrapper.Client#CLIENT Client - function( Client ) - - self:E( Client.UnitName ) - if Client:IsAlive() then - local NotInRunwayZone = true - for ZoneRunwayID, ZoneRunway in pairs( Airbase.ZoneRunways ) do - NotInRunwayZone = ( Client:IsNotInZone( ZoneRunway ) == true ) and NotInRunwayZone or false - end - - if NotInRunwayZone then - local Taxi = self:GetState( self, "Taxi" ) - self:E( Taxi ) - if Taxi == false then - Client:Message( "Welcome at " .. AirbaseID .. ". The maximum taxiing speed is " .. Airbase.MaximumSpeed " km/h.", 20, "ATC" ) - self:SetState( self, "Taxi", true ) - end - - -- TODO: GetVelocityKMH function usage - local VelocityVec3 = Client:GetVelocity() - local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - local Velocity = Velocity * 3.6 -- now it is in km/h. - -- MESSAGE:New( "Velocity = " .. Velocity, 1 ):ToAll() - local IsAboveRunway = Client:IsAboveRunway() - local IsOnGround = Client:InAir() == false - self:T( IsAboveRunway, IsOnGround ) - - if IsAboveRunway and IsOnGround then - - if Velocity > Airbase.MaximumSpeed then - local IsSpeeding = Client:GetState( self, "Speeding" ) - - if IsSpeeding == true then - local SpeedingWarnings = Client:GetState( self, "Warnings" ) - self:T( SpeedingWarnings ) - - if SpeedingWarnings <= 3 then - Client:Message( "You are speeding on the taxiway! Slow down or you will be removed from this airbase! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Warning " .. SpeedingWarnings .. " / 3" ) - Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) - else - MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() - Client:GetGroup():Destroy() - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - end - - else - Client:Message( "You are speeding on the taxiway, slow down now! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Attention! " ) - Client:SetState( self, "Speeding", true ) - Client:SetState( self, "Warnings", 1 ) - end - - else - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - end - end - - else - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - local Taxi = self:GetState( self, "Taxi" ) - if Taxi == true then - Client:Message( "You have progressed to the runway ... Await take-off clearance ...", 20, "ATC" ) - self:SetState( self, "Taxi", false ) - end - end - end - end - ) - end - end - - return true -end - - ---- @type AIRBASEPOLICE_CAUCASUS --- @field Core.Set#SET_CLIENT SetClient --- @extends #AIRBASEPOLICE_BASE - -AIRBASEPOLICE_CAUCASUS = { - ClassName = "AIRBASEPOLICE_CAUCASUS", - Airbases = { - AnapaVityazevo = { - PointsBoundary = { - [1]={["y"]=242234.85714287,["x"]=-6616.5714285726,}, - [2]={["y"]=241060.57142858,["x"]=-5585.142857144,}, - [3]={["y"]=243806.2857143,["x"]=-3962.2857142868,}, - [4]={["y"]=245240.57142858,["x"]=-4816.5714285726,}, - [5]={["y"]=244783.42857144,["x"]=-5630.8571428583,}, - [6]={["y"]=243800.57142858,["x"]=-5065.142857144,}, - [7]={["y"]=242232.00000001,["x"]=-6622.2857142868,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=242140.57142858,["x"]=-6478.8571428583,}, - [2]={["y"]=242188.57142858,["x"]=-6522.0000000011,}, - [3]={["y"]=244124.2857143,["x"]=-4344.0000000011,}, - [4]={["y"]=244068.2857143,["x"]=-4296.5714285726,}, - [5]={["y"]=242140.57142858,["x"]=-6480.0000000011,} - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Batumi = { - PointsBoundary = { - [1]={["y"]=617567.14285714,["x"]=-355313.14285715,}, - [2]={["y"]=616181.42857142,["x"]=-354800.28571429,}, - [3]={["y"]=616007.14285714,["x"]=-355128.85714286,}, - [4]={["y"]=618230,["x"]=-356914.57142858,}, - [5]={["y"]=618727.14285714,["x"]=-356166,}, - [6]={["y"]=617572.85714285,["x"]=-355308.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=616442.28571429,["x"]=-355090.28571429,}, - [2]={["y"]=618450.57142857,["x"]=-356522,}, - [3]={["y"]=618407.71428571,["x"]=-356584.85714286,}, - [4]={["y"]=618361.99999999,["x"]=-356554.85714286,}, - [5]={["y"]=618324.85714285,["x"]=-356599.14285715,}, - [6]={["y"]=618250.57142856,["x"]=-356543.42857143,}, - [7]={["y"]=618257.7142857,["x"]=-356496.28571429,}, - [8]={["y"]=618237.7142857,["x"]=-356459.14285715,}, - [9]={["y"]=616555.71428571,["x"]=-355258.85714286,}, - [10]={["y"]=616486.28571428,["x"]=-355280.57142858,}, - [11]={["y"]=616410.57142856,["x"]=-355227.71428572,}, - [12]={["y"]=616441.99999999,["x"]=-355179.14285715,}, - [13]={["y"]=616401.99999999,["x"]=-355147.71428572,}, - [14]={["y"]=616441.42857142,["x"]=-355092.57142858,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Beslan = { - PointsBoundary = { - [1]={["y"]=842082.57142857,["x"]=-148445.14285715,}, - [2]={["y"]=845237.71428572,["x"]=-148639.71428572,}, - [3]={["y"]=845232,["x"]=-148765.42857143,}, - [4]={["y"]=844220.57142857,["x"]=-149168.28571429,}, - [5]={["y"]=843274.85714286,["x"]=-149125.42857143,}, - [6]={["y"]=842077.71428572,["x"]=-148554,}, - [7]={["y"]=842083.42857143,["x"]=-148445.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=842104.57142857,["x"]=-148460.57142857,}, - [2]={["y"]=845225.71428572,["x"]=-148656,}, - [3]={["y"]=845220.57142858,["x"]=-148750,}, - [4]={["y"]=842098.85714286,["x"]=-148556.28571429,}, - [5]={["y"]=842104,["x"]=-148460.28571429,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Gelendzhik = { - PointsBoundary = { - [1]={["y"]=297856.00000001,["x"]=-51151.428571429,}, - [2]={["y"]=299044.57142858,["x"]=-49720.000000001,}, - [3]={["y"]=298861.71428572,["x"]=-49580.000000001,}, - [4]={["y"]=298198.85714286,["x"]=-49842.857142858,}, - [5]={["y"]=297990.28571429,["x"]=-50151.428571429,}, - [6]={["y"]=297696.00000001,["x"]=-51054.285714286,}, - [7]={["y"]=297850.28571429,["x"]=-51160.000000001,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=297834.00000001,["x"]=-51107.428571429,}, - [2]={["y"]=297786.57142858,["x"]=-51068.857142858,}, - [3]={["y"]=298946.57142858,["x"]=-49686.000000001,}, - [4]={["y"]=298993.14285715,["x"]=-49725.714285715,}, - [5]={["y"]=297835.14285715,["x"]=-51107.714285715,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Gudauta = { - PointsBoundary = { - [1]={["y"]=517246.57142857,["x"]=-197850.28571429,}, - [2]={["y"]=516749.42857142,["x"]=-198070.28571429,}, - [3]={["y"]=515755.14285714,["x"]=-197598.85714286,}, - [4]={["y"]=515369.42857142,["x"]=-196538.85714286,}, - [5]={["y"]=515623.71428571,["x"]=-195618.85714286,}, - [6]={["y"]=515946.57142857,["x"]=-195510.28571429,}, - [7]={["y"]=517243.71428571,["x"]=-197858.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=517096.57142857,["x"]=-197804.57142857,}, - [2]={["y"]=515880.85714285,["x"]=-195590.28571429,}, - [3]={["y"]=515812.28571428,["x"]=-195628.85714286,}, - [4]={["y"]=517036.57142857,["x"]=-197834.57142857,}, - [5]={["y"]=517097.99999999,["x"]=-197807.42857143,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Kobuleti = { - PointsBoundary = { - [1]={["y"]=634427.71428571,["x"]=-318290.28571429,}, - [2]={["y"]=635033.42857143,["x"]=-317550.2857143,}, - [3]={["y"]=635864.85714286,["x"]=-317333.14285715,}, - [4]={["y"]=636967.71428571,["x"]=-317261.71428572,}, - [5]={["y"]=637144.85714286,["x"]=-317913.14285715,}, - [6]={["y"]=634630.57142857,["x"]=-318687.42857144,}, - [7]={["y"]=634424.85714286,["x"]=-318290.2857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=634509.71428571,["x"]=-318339.42857144,}, - [2]={["y"]=636767.42857143,["x"]=-317516.57142858,}, - [3]={["y"]=636790,["x"]=-317575.71428572,}, - [4]={["y"]=634531.42857143,["x"]=-318398.00000001,}, - [5]={["y"]=634510.28571429,["x"]=-318339.71428572,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - KrasnodarCenter = { - PointsBoundary = { - [1]={["y"]=366680.28571429,["x"]=11699.142857142,}, - [2]={["y"]=366654.28571429,["x"]=11225.142857142,}, - [3]={["y"]=367497.14285715,["x"]=11082.285714285,}, - [4]={["y"]=368025.71428572,["x"]=10396.57142857,}, - [5]={["y"]=369854.28571429,["x"]=11367.999999999,}, - [6]={["y"]=369840.00000001,["x"]=11910.857142856,}, - [7]={["y"]=366682.57142858,["x"]=11697.999999999,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=369205.42857144,["x"]=11789.142857142,}, - [2]={["y"]=369209.71428572,["x"]=11714.857142856,}, - [3]={["y"]=366699.71428572,["x"]=11581.714285713,}, - [4]={["y"]=366698.28571429,["x"]=11659.142857142,}, - [5]={["y"]=369208.85714286,["x"]=11788.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - KrasnodarPashkovsky = { - PointsBoundary = { - [1]={["y"]=386754,["x"]=6476.5714285703,}, - [2]={["y"]=389182.57142858,["x"]=8722.2857142846,}, - [3]={["y"]=388832.57142858,["x"]=9086.5714285703,}, - [4]={["y"]=386961.14285715,["x"]=7707.9999999989,}, - [5]={["y"]=385404,["x"]=9179.4285714274,}, - [6]={["y"]=383239.71428572,["x"]=7386.5714285703,}, - [7]={["y"]=383954,["x"]=6486.5714285703,}, - [8]={["y"]=385775.42857143,["x"]=8097.9999999989,}, - [9]={["y"]=386804,["x"]=7319.4285714274,}, - [10]={["y"]=386375.42857143,["x"]=6797.9999999989,}, - [11]={["y"]=386746.85714286,["x"]=6472.2857142846,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=385891.14285715,["x"]=8416.5714285703,}, - [2]={["y"]=385842.28571429,["x"]=8467.9999999989,}, - [3]={["y"]=384180.85714286,["x"]=6917.1428571417,}, - [4]={["y"]=384228.57142858,["x"]=6867.7142857132,}, - [5]={["y"]=385891.14285715,["x"]=8416.5714285703,}, - }, - [2] = { - [1]={["y"]=386714.85714286,["x"]=6674.857142856,}, - [2]={["y"]=386757.71428572,["x"]=6627.7142857132,}, - [3]={["y"]=389028.57142858,["x"]=8741.4285714275,}, - [4]={["y"]=388981.71428572,["x"]=8790.5714285703,}, - [5]={["y"]=386714.57142858,["x"]=6674.5714285703,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Krymsk = { - PointsBoundary = { - [1]={["y"]=293338.00000001,["x"]=-7575.4285714297,}, - [2]={["y"]=295199.42857144,["x"]=-5434.0000000011,}, - [3]={["y"]=295595.14285715,["x"]=-6239.7142857154,}, - [4]={["y"]=294152.2857143,["x"]=-8325.4285714297,}, - [5]={["y"]=293345.14285715,["x"]=-7596.8571428582,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=293522.00000001,["x"]=-7567.4285714297,}, - [2]={["y"]=293578.57142858,["x"]=-7616.0000000011,}, - [3]={["y"]=295246.00000001,["x"]=-5591.142857144,}, - [4]={["y"]=295187.71428573,["x"]=-5546.0000000011,}, - [5]={["y"]=293523.14285715,["x"]=-7568.2857142868,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Kutaisi = { - PointsBoundary = { - [1]={["y"]=682087.42857143,["x"]=-284512.85714286,}, - [2]={["y"]=685387.42857143,["x"]=-283662.85714286,}, - [3]={["y"]=685294.57142857,["x"]=-284977.14285715,}, - [4]={["y"]=682744.57142857,["x"]=-286505.71428572,}, - [5]={["y"]=682094.57142857,["x"]=-284527.14285715,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=682638,["x"]=-285202.28571429,}, - [2]={["y"]=685050.28571429,["x"]=-284507.42857144,}, - [3]={["y"]=685068.85714286,["x"]=-284578.85714286,}, - [4]={["y"]=682657.42857143,["x"]=-285264.28571429,}, - [5]={["y"]=682638.28571429,["x"]=-285202.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - MaykopKhanskaya = { - PointsBoundary = { - [1]={["y"]=456876.28571429,["x"]=-27665.42857143,}, - [2]={["y"]=457800,["x"]=-28392.857142858,}, - [3]={["y"]=459368.57142857,["x"]=-26378.571428573,}, - [4]={["y"]=459425.71428572,["x"]=-25242.857142858,}, - [5]={["y"]=458961.42857143,["x"]=-24964.285714287,}, - [6]={["y"]=456878.57142857,["x"]=-27667.714285715,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=457005.42857143,["x"]=-27668.000000001,}, - [2]={["y"]=459028.85714286,["x"]=-25168.857142858,}, - [3]={["y"]=459082.57142857,["x"]=-25216.857142858,}, - [4]={["y"]=457060,["x"]=-27714.285714287,}, - [5]={["y"]=457004.57142857,["x"]=-27669.714285715,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - MineralnyeVody = { - PointsBoundary = { - [1]={["y"]=703857.14285714,["x"]=-50226.000000002,}, - [2]={["y"]=707385.71428571,["x"]=-51911.714285716,}, - [3]={["y"]=707595.71428571,["x"]=-51434.857142859,}, - [4]={["y"]=707900,["x"]=-51568.857142859,}, - [5]={["y"]=707542.85714286,["x"]=-52326.000000002,}, - [6]={["y"]=706628.57142857,["x"]=-52568.857142859,}, - [7]={["y"]=705142.85714286,["x"]=-51790.285714288,}, - [8]={["y"]=703678.57142857,["x"]=-50611.714285716,}, - [9]={["y"]=703857.42857143,["x"]=-50226.857142859,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=703904,["x"]=-50352.571428573,}, - [2]={["y"]=707596.28571429,["x"]=-52094.571428573,}, - [3]={["y"]=707560.57142858,["x"]=-52161.714285716,}, - [4]={["y"]=703871.71428572,["x"]=-50420.571428573,}, - [5]={["y"]=703902,["x"]=-50352.000000002,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Mozdok = { - PointsBoundary = { - [1]={["y"]=832123.42857143,["x"]=-83608.571428573,}, - [2]={["y"]=835916.28571429,["x"]=-83144.285714288,}, - [3]={["y"]=835474.28571429,["x"]=-84170.571428573,}, - [4]={["y"]=832911.42857143,["x"]=-84470.571428573,}, - [5]={["y"]=832487.71428572,["x"]=-85565.714285716,}, - [6]={["y"]=831573.42857143,["x"]=-85351.42857143,}, - [7]={["y"]=832123.71428572,["x"]=-83610.285714288,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=832201.14285715,["x"]=-83699.428571431,}, - [2]={["y"]=832212.57142857,["x"]=-83780.571428574,}, - [3]={["y"]=835730.28571429,["x"]=-83335.714285717,}, - [4]={["y"]=835718.85714286,["x"]=-83246.571428574,}, - [5]={["y"]=832200.57142857,["x"]=-83700.000000002,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Nalchik = { - PointsBoundary = { - [1]={["y"]=759370,["x"]=-125502.85714286,}, - [2]={["y"]=761384.28571429,["x"]=-124177.14285714,}, - [3]={["y"]=761472.85714286,["x"]=-124325.71428572,}, - [4]={["y"]=761092.85714286,["x"]=-125048.57142857,}, - [5]={["y"]=760295.71428572,["x"]=-125685.71428572,}, - [6]={["y"]=759444.28571429,["x"]=-125734.28571429,}, - [7]={["y"]=759375.71428572,["x"]=-125511.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=759454.28571429,["x"]=-125551.42857143,}, - [2]={["y"]=759492.85714286,["x"]=-125610.85714286,}, - [3]={["y"]=761406.28571429,["x"]=-124304.28571429,}, - [4]={["y"]=761361.14285714,["x"]=-124239.71428572,}, - [5]={["y"]=759456,["x"]=-125552.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Novorossiysk = { - PointsBoundary = { - [1]={["y"]=278677.71428573,["x"]=-41656.571428572,}, - [2]={["y"]=278446.2857143,["x"]=-41453.714285715,}, - [3]={["y"]=278989.14285716,["x"]=-40188.000000001,}, - [4]={["y"]=279717.71428573,["x"]=-39968.000000001,}, - [5]={["y"]=280020.57142859,["x"]=-40208.000000001,}, - [6]={["y"]=278674.85714287,["x"]=-41660.857142858,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=278673.14285716,["x"]=-41615.142857144,}, - [2]={["y"]=278625.42857144,["x"]=-41570.571428572,}, - [3]={["y"]=279835.42857144,["x"]=-40226.000000001,}, - [4]={["y"]=279882.2857143,["x"]=-40270.000000001,}, - [5]={["y"]=278672.00000001,["x"]=-41614.857142858,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SenakiKolkhi = { - PointsBoundary = { - [1]={["y"]=646036.57142857,["x"]=-281778.85714286,}, - [2]={["y"]=646045.14285714,["x"]=-281191.71428571,}, - [3]={["y"]=647032.28571429,["x"]=-280598.85714285,}, - [4]={["y"]=647669.42857143,["x"]=-281273.14285714,}, - [5]={["y"]=648323.71428571,["x"]=-281370.28571428,}, - [6]={["y"]=648520.85714286,["x"]=-281978.85714285,}, - [7]={["y"]=646039.42857143,["x"]=-281783.14285714,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=646060.85714285,["x"]=-281736,}, - [2]={["y"]=646056.57142857,["x"]=-281631.71428571,}, - [3]={["y"]=648442.28571428,["x"]=-281840.28571428,}, - [4]={["y"]=648432.28571428,["x"]=-281918.85714286,}, - [5]={["y"]=646063.71428571,["x"]=-281738.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SochiAdler = { - PointsBoundary = { - [1]={["y"]=460642.28571428,["x"]=-164861.71428571,}, - [2]={["y"]=462820.85714285,["x"]=-163368.85714286,}, - [3]={["y"]=463649.42857142,["x"]=-163340.28571429,}, - [4]={["y"]=463835.14285714,["x"]=-164040.28571429,}, - [5]={["y"]=462535.14285714,["x"]=-165654.57142857,}, - [6]={["y"]=460678,["x"]=-165247.42857143,}, - [7]={["y"]=460635.14285714,["x"]=-164876,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=460831.42857143,["x"]=-165180,}, - [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, - [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, - [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, - [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, - }, - [2] = { - [1]={["y"]=460831.42857143,["x"]=-165180,}, - [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, - [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, - [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, - [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Soganlug = { - PointsBoundary = { - [1]={["y"]=894530.85714286,["x"]=-316928.28571428,}, - [2]={["y"]=896422.28571428,["x"]=-318622.57142857,}, - [3]={["y"]=896090.85714286,["x"]=-318934,}, - [4]={["y"]=894019.42857143,["x"]=-317119.71428571,}, - [5]={["y"]=894533.71428571,["x"]=-316925.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=894525.71428571,["x"]=-316964,}, - [2]={["y"]=896363.14285714,["x"]=-318634.28571428,}, - [3]={["y"]=896299.14285714,["x"]=-318702.85714286,}, - [4]={["y"]=894464,["x"]=-317031.71428571,}, - [5]={["y"]=894524.57142857,["x"]=-316963.71428571,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SukhumiBabushara = { - PointsBoundary = { - [1]={["y"]=562541.14285714,["x"]=-219852.28571429,}, - [2]={["y"]=562691.14285714,["x"]=-219395.14285714,}, - [3]={["y"]=564326.85714286,["x"]=-219523.71428571,}, - [4]={["y"]=566262.57142857,["x"]=-221166.57142857,}, - [5]={["y"]=566069.71428571,["x"]=-221580.85714286,}, - [6]={["y"]=562534,["x"]=-219873.71428571,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=562684,["x"]=-219779.71428571,}, - [2]={["y"]=562717.71428571,["x"]=-219718,}, - [3]={["y"]=566046.85714286,["x"]=-221376.57142857,}, - [4]={["y"]=566012.28571428,["x"]=-221446.57142857,}, - [5]={["y"]=562684.57142857,["x"]=-219782.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - TbilisiLochini = { - PointsBoundary = { - [1]={["y"]=895172.85714286,["x"]=-314667.42857143,}, - [2]={["y"]=895337.42857143,["x"]=-314143.14285714,}, - [3]={["y"]=895990.28571429,["x"]=-314036,}, - [4]={["y"]=897730.28571429,["x"]=-315284.57142857,}, - [5]={["y"]=897901.71428571,["x"]=-316284.57142857,}, - [6]={["y"]=897684.57142857,["x"]=-316618.85714286,}, - [7]={["y"]=895173.14285714,["x"]=-314667.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=895261.14285715,["x"]=-314652.28571428,}, - [2]={["y"]=897654.57142857,["x"]=-316523.14285714,}, - [3]={["y"]=897711.71428571,["x"]=-316450.28571429,}, - [4]={["y"]=895327.42857143,["x"]=-314568.85714286,}, - [5]={["y"]=895261.71428572,["x"]=-314656,}, - }, - [2] = { - [1]={["y"]=895605.71428572,["x"]=-314724.57142857,}, - [2]={["y"]=897639.71428572,["x"]=-316148,}, - [3]={["y"]=897683.42857143,["x"]=-316087.14285714,}, - [4]={["y"]=895650,["x"]=-314660,}, - [5]={["y"]=895606,["x"]=-314724.85714286,} - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Vaziani = { - PointsBoundary = { - [1]={["y"]=902122,["x"]=-318163.71428572,}, - [2]={["y"]=902678.57142857,["x"]=-317594,}, - [3]={["y"]=903275.71428571,["x"]=-317405.42857143,}, - [4]={["y"]=903418.57142857,["x"]=-317891.14285714,}, - [5]={["y"]=904292.85714286,["x"]=-318748.28571429,}, - [6]={["y"]=904542,["x"]=-319740.85714286,}, - [7]={["y"]=904042,["x"]=-320166.57142857,}, - [8]={["y"]=902121.42857143,["x"]=-318164.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=902239.14285714,["x"]=-318190.85714286,}, - [2]={["y"]=904014.28571428,["x"]=-319994.57142857,}, - [3]={["y"]=904064.85714285,["x"]=-319945.14285715,}, - [4]={["y"]=902294.57142857,["x"]=-318146,}, - [5]={["y"]=902247.71428571,["x"]=-318190.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - }, -} - ---- Creates a new AIRBASEPOLICE_CAUCASUS object. --- @param #AIRBASEPOLICE_CAUCASUS self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @return #AIRBASEPOLICE_CAUCASUS self -function AIRBASEPOLICE_CAUCASUS:New( SetClient ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) - - -- -- AnapaVityazevo - -- local AnapaVityazevoBoundary = GROUP:FindByName( "AnapaVityazevo Boundary" ) - -- self.Airbases.AnapaVityazevo.ZoneBoundary = ZONE_POLYGON:New( "AnapaVityazevo Boundary", AnapaVityazevoBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local AnapaVityazevoRunway1 = GROUP:FindByName( "AnapaVityazevo Runway 1" ) - -- self.Airbases.AnapaVityazevo.ZoneRunways[1] = ZONE_POLYGON:New( "AnapaVityazevo Runway 1", AnapaVityazevoRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Batumi - -- local BatumiBoundary = GROUP:FindByName( "Batumi Boundary" ) - -- self.Airbases.Batumi.ZoneBoundary = ZONE_POLYGON:New( "Batumi Boundary", BatumiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local BatumiRunway1 = GROUP:FindByName( "Batumi Runway 1" ) - -- self.Airbases.Batumi.ZoneRunways[1] = ZONE_POLYGON:New( "Batumi Runway 1", BatumiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Beslan - -- local BeslanBoundary = GROUP:FindByName( "Beslan Boundary" ) - -- self.Airbases.Beslan.ZoneBoundary = ZONE_POLYGON:New( "Beslan Boundary", BeslanBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local BeslanRunway1 = GROUP:FindByName( "Beslan Runway 1" ) - -- self.Airbases.Beslan.ZoneRunways[1] = ZONE_POLYGON:New( "Beslan Runway 1", BeslanRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Gelendzhik - -- local GelendzhikBoundary = GROUP:FindByName( "Gelendzhik Boundary" ) - -- self.Airbases.Gelendzhik.ZoneBoundary = ZONE_POLYGON:New( "Gelendzhik Boundary", GelendzhikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local GelendzhikRunway1 = GROUP:FindByName( "Gelendzhik Runway 1" ) - -- self.Airbases.Gelendzhik.ZoneRunways[1] = ZONE_POLYGON:New( "Gelendzhik Runway 1", GelendzhikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Gudauta - -- local GudautaBoundary = GROUP:FindByName( "Gudauta Boundary" ) - -- self.Airbases.Gudauta.ZoneBoundary = ZONE_POLYGON:New( "Gudauta Boundary", GudautaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local GudautaRunway1 = GROUP:FindByName( "Gudauta Runway 1" ) - -- self.Airbases.Gudauta.ZoneRunways[1] = ZONE_POLYGON:New( "Gudauta Runway 1", GudautaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Kobuleti - -- local KobuletiBoundary = GROUP:FindByName( "Kobuleti Boundary" ) - -- self.Airbases.Kobuleti.ZoneBoundary = ZONE_POLYGON:New( "Kobuleti Boundary", KobuletiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KobuletiRunway1 = GROUP:FindByName( "Kobuleti Runway 1" ) - -- self.Airbases.Kobuleti.ZoneRunways[1] = ZONE_POLYGON:New( "Kobuleti Runway 1", KobuletiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- KrasnodarCenter - -- local KrasnodarCenterBoundary = GROUP:FindByName( "KrasnodarCenter Boundary" ) - -- self.Airbases.KrasnodarCenter.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarCenter Boundary", KrasnodarCenterBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrasnodarCenterRunway1 = GROUP:FindByName( "KrasnodarCenter Runway 1" ) - -- self.Airbases.KrasnodarCenter.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarCenter Runway 1", KrasnodarCenterRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- KrasnodarPashkovsky - -- local KrasnodarPashkovskyBoundary = GROUP:FindByName( "KrasnodarPashkovsky Boundary" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarPashkovsky Boundary", KrasnodarPashkovskyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrasnodarPashkovskyRunway1 = GROUP:FindByName( "KrasnodarPashkovsky Runway 1" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 1", KrasnodarPashkovskyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- local KrasnodarPashkovskyRunway2 = GROUP:FindByName( "KrasnodarPashkovsky Runway 2" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[2] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 2", KrasnodarPashkovskyRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Krymsk - -- local KrymskBoundary = GROUP:FindByName( "Krymsk Boundary" ) - -- self.Airbases.Krymsk.ZoneBoundary = ZONE_POLYGON:New( "Krymsk Boundary", KrymskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrymskRunway1 = GROUP:FindByName( "Krymsk Runway 1" ) - -- self.Airbases.Krymsk.ZoneRunways[1] = ZONE_POLYGON:New( "Krymsk Runway 1", KrymskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Kutaisi - -- local KutaisiBoundary = GROUP:FindByName( "Kutaisi Boundary" ) - -- self.Airbases.Kutaisi.ZoneBoundary = ZONE_POLYGON:New( "Kutaisi Boundary", KutaisiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KutaisiRunway1 = GROUP:FindByName( "Kutaisi Runway 1" ) - -- self.Airbases.Kutaisi.ZoneRunways[1] = ZONE_POLYGON:New( "Kutaisi Runway 1", KutaisiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- MaykopKhanskaya - -- local MaykopKhanskayaBoundary = GROUP:FindByName( "MaykopKhanskaya Boundary" ) - -- self.Airbases.MaykopKhanskaya.ZoneBoundary = ZONE_POLYGON:New( "MaykopKhanskaya Boundary", MaykopKhanskayaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MaykopKhanskayaRunway1 = GROUP:FindByName( "MaykopKhanskaya Runway 1" ) - -- self.Airbases.MaykopKhanskaya.ZoneRunways[1] = ZONE_POLYGON:New( "MaykopKhanskaya Runway 1", MaykopKhanskayaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- MineralnyeVody - -- local MineralnyeVodyBoundary = GROUP:FindByName( "MineralnyeVody Boundary" ) - -- self.Airbases.MineralnyeVody.ZoneBoundary = ZONE_POLYGON:New( "MineralnyeVody Boundary", MineralnyeVodyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MineralnyeVodyRunway1 = GROUP:FindByName( "MineralnyeVody Runway 1" ) - -- self.Airbases.MineralnyeVody.ZoneRunways[1] = ZONE_POLYGON:New( "MineralnyeVody Runway 1", MineralnyeVodyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Mozdok - -- local MozdokBoundary = GROUP:FindByName( "Mozdok Boundary" ) - -- self.Airbases.Mozdok.ZoneBoundary = ZONE_POLYGON:New( "Mozdok Boundary", MozdokBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MozdokRunway1 = GROUP:FindByName( "Mozdok Runway 1" ) - -- self.Airbases.Mozdok.ZoneRunways[1] = ZONE_POLYGON:New( "Mozdok Runway 1", MozdokRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Nalchik - -- local NalchikBoundary = GROUP:FindByName( "Nalchik Boundary" ) - -- self.Airbases.Nalchik.ZoneBoundary = ZONE_POLYGON:New( "Nalchik Boundary", NalchikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local NalchikRunway1 = GROUP:FindByName( "Nalchik Runway 1" ) - -- self.Airbases.Nalchik.ZoneRunways[1] = ZONE_POLYGON:New( "Nalchik Runway 1", NalchikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Novorossiysk - -- local NovorossiyskBoundary = GROUP:FindByName( "Novorossiysk Boundary" ) - -- self.Airbases.Novorossiysk.ZoneBoundary = ZONE_POLYGON:New( "Novorossiysk Boundary", NovorossiyskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local NovorossiyskRunway1 = GROUP:FindByName( "Novorossiysk Runway 1" ) - -- self.Airbases.Novorossiysk.ZoneRunways[1] = ZONE_POLYGON:New( "Novorossiysk Runway 1", NovorossiyskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SenakiKolkhi - -- local SenakiKolkhiBoundary = GROUP:FindByName( "SenakiKolkhi Boundary" ) - -- self.Airbases.SenakiKolkhi.ZoneBoundary = ZONE_POLYGON:New( "SenakiKolkhi Boundary", SenakiKolkhiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SenakiKolkhiRunway1 = GROUP:FindByName( "SenakiKolkhi Runway 1" ) - -- self.Airbases.SenakiKolkhi.ZoneRunways[1] = ZONE_POLYGON:New( "SenakiKolkhi Runway 1", SenakiKolkhiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SochiAdler - -- local SochiAdlerBoundary = GROUP:FindByName( "SochiAdler Boundary" ) - -- self.Airbases.SochiAdler.ZoneBoundary = ZONE_POLYGON:New( "SochiAdler Boundary", SochiAdlerBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SochiAdlerRunway1 = GROUP:FindByName( "SochiAdler Runway 1" ) - -- self.Airbases.SochiAdler.ZoneRunways[1] = ZONE_POLYGON:New( "SochiAdler Runway 1", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- local SochiAdlerRunway2 = GROUP:FindByName( "SochiAdler Runway 2" ) - -- self.Airbases.SochiAdler.ZoneRunways[2] = ZONE_POLYGON:New( "SochiAdler Runway 2", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Soganlug - -- local SoganlugBoundary = GROUP:FindByName( "Soganlug Boundary" ) - -- self.Airbases.Soganlug.ZoneBoundary = ZONE_POLYGON:New( "Soganlug Boundary", SoganlugBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SoganlugRunway1 = GROUP:FindByName( "Soganlug Runway 1" ) - -- self.Airbases.Soganlug.ZoneRunways[1] = ZONE_POLYGON:New( "Soganlug Runway 1", SoganlugRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SukhumiBabushara - -- local SukhumiBabusharaBoundary = GROUP:FindByName( "SukhumiBabushara Boundary" ) - -- self.Airbases.SukhumiBabushara.ZoneBoundary = ZONE_POLYGON:New( "SukhumiBabushara Boundary", SukhumiBabusharaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SukhumiBabusharaRunway1 = GROUP:FindByName( "SukhumiBabushara Runway 1" ) - -- self.Airbases.SukhumiBabushara.ZoneRunways[1] = ZONE_POLYGON:New( "SukhumiBabushara Runway 1", SukhumiBabusharaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- TbilisiLochini - -- local TbilisiLochiniBoundary = GROUP:FindByName( "TbilisiLochini Boundary" ) - -- self.Airbases.TbilisiLochini.ZoneBoundary = ZONE_POLYGON:New( "TbilisiLochini Boundary", TbilisiLochiniBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local TbilisiLochiniRunway1 = GROUP:FindByName( "TbilisiLochini Runway 1" ) - -- self.Airbases.TbilisiLochini.ZoneRunways[1] = ZONE_POLYGON:New( "TbilisiLochini Runway 1", TbilisiLochiniRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- local TbilisiLochiniRunway2 = GROUP:FindByName( "TbilisiLochini Runway 2" ) - -- self.Airbases.TbilisiLochini.ZoneRunways[2] = ZONE_POLYGON:New( "TbilisiLochini Runway 2", TbilisiLochiniRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Vaziani - -- local VazianiBoundary = GROUP:FindByName( "Vaziani Boundary" ) - -- self.Airbases.Vaziani.ZoneBoundary = ZONE_POLYGON:New( "Vaziani Boundary", VazianiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local VazianiRunway1 = GROUP:FindByName( "Vaziani Runway 1" ) - -- self.Airbases.Vaziani.ZoneRunways[1] = ZONE_POLYGON:New( "Vaziani Runway 1", VazianiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - - - -- Template - -- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) - -- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) - -- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - - return self - -end - - - - ---- @type AIRBASEPOLICE_NEVADA --- @extends Functional.AirbasePolice#AIRBASEPOLICE_BASE -AIRBASEPOLICE_NEVADA = { - ClassName = "AIRBASEPOLICE_NEVADA", - Airbases = { - Nellis = { - PointsBoundary = { - [1]={["y"]=-17814.714285714,["x"]=-399823.14285714,}, - [2]={["y"]=-16875.857142857,["x"]=-398763.14285714,}, - [3]={["y"]=-16251.571428571,["x"]=-398988.85714286,}, - [4]={["y"]=-16163,["x"]=-398693.14285714,}, - [5]={["y"]=-16328.714285714,["x"]=-398034.57142857,}, - [6]={["y"]=-15943,["x"]=-397571.71428571,}, - [7]={["y"]=-15711.571428571,["x"]=-397551.71428571,}, - [8]={["y"]=-15748.714285714,["x"]=-396806,}, - [9]={["y"]=-16288.714285714,["x"]=-396517.42857143,}, - [10]={["y"]=-16751.571428571,["x"]=-396308.85714286,}, - [11]={["y"]=-17263,["x"]=-396234.57142857,}, - [12]={["y"]=-17577.285714286,["x"]=-396640.28571429,}, - [13]={["y"]=-17614.428571429,["x"]=-397400.28571429,}, - [14]={["y"]=-19405.857142857,["x"]=-399428.85714286,}, - [15]={["y"]=-19234.428571429,["x"]=-399683.14285714,}, - [16]={["y"]=-18708.714285714,["x"]=-399408.85714286,}, - [17]={["y"]=-18397.285714286,["x"]=-399657.42857143,}, - [18]={["y"]=-17814.428571429,["x"]=-399823.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-18687,["x"]=-399380.28571429,}, - [2]={["y"]=-18620.714285714,["x"]=-399436.85714286,}, - [3]={["y"]=-16217.857142857,["x"]=-396596.85714286,}, - [4]={["y"]=-16300.142857143,["x"]=-396530,}, - [5]={["y"]=-18687,["x"]=-399380.85714286,}, - }, - [2] = { - [1]={["y"]=-18451.571428572,["x"]=-399580.57142857,}, - [2]={["y"]=-18392.142857143,["x"]=-399628.57142857,}, - [3]={["y"]=-16011,["x"]=-396806.85714286,}, - [4]={["y"]=-16074.714285714,["x"]=-396751.71428572,}, - [5]={["y"]=-18451.571428572,["x"]=-399580.85714285,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - McCarran = { - PointsBoundary = { - [1]={["y"]=-29455.285714286,["x"]=-416277.42857142,}, - [2]={["y"]=-28860.142857143,["x"]=-416492,}, - [3]={["y"]=-25044.428571429,["x"]=-416344.85714285,}, - [4]={["y"]=-24580.142857143,["x"]=-415959.14285714,}, - [5]={["y"]=-25073,["x"]=-415630.57142857,}, - [6]={["y"]=-25087.285714286,["x"]=-415130.57142857,}, - [7]={["y"]=-25830.142857143,["x"]=-414866.28571428,}, - [8]={["y"]=-26658.714285715,["x"]=-414880.57142857,}, - [9]={["y"]=-26973,["x"]=-415273.42857142,}, - [10]={["y"]=-27380.142857143,["x"]=-415187.71428571,}, - [11]={["y"]=-27715.857142857,["x"]=-414144.85714285,}, - [12]={["y"]=-27551.571428572,["x"]=-413473.42857142,}, - [13]={["y"]=-28630.142857143,["x"]=-413201.99999999,}, - [14]={["y"]=-29494.428571429,["x"]=-415437.71428571,}, - [15]={["y"]=-29455.571428572,["x"]=-416277.71428571,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-29408.428571429,["x"]=-416016.28571428,}, - [2]={["y"]=-29408.142857144,["x"]=-416105.42857142,}, - [3]={["y"]=-24680.714285715,["x"]=-416003.14285713,}, - [4]={["y"]=-24681.857142858,["x"]=-415926.57142856,}, - [5]={["y"]=-29408.42857143,["x"]=-416016.57142856,}, - }, - [2] = { - [1]={["y"]=-28575.571428572,["x"]=-416303.14285713,}, - [2]={["y"]=-28575.571428572,["x"]=-416382.57142856,}, - [3]={["y"]=-25111.000000001,["x"]=-416309.7142857,}, - [4]={["y"]=-25111.000000001,["x"]=-416249.14285713,}, - [5]={["y"]=-28575.571428572,["x"]=-416303.7142857,}, - }, - [3] = { - [1]={["y"]=-29331.000000001,["x"]=-416275.42857141,}, - [2]={["y"]=-29259.000000001,["x"]=-416306.85714284,}, - [3]={["y"]=-28005.571428572,["x"]=-413449.7142857,}, - [4]={["y"]=-28068.714285715,["x"]=-413422.85714284,}, - [5]={["y"]=-29331.000000001,["x"]=-416275.7142857,}, - }, - [4] = { - [1]={["y"]=-29073.285714286,["x"]=-416386.57142856,}, - [2]={["y"]=-28997.285714286,["x"]=-416417.42857141,}, - [3]={["y"]=-27697.571428572,["x"]=-413464.57142856,}, - [4]={["y"]=-27767.857142858,["x"]=-413434.28571427,}, - [5]={["y"]=-29073.000000001,["x"]=-416386.85714284,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Creech = { - PointsBoundary = { - [1]={["y"]=-74522.714285715,["x"]=-360887.99999998,}, - [2]={["y"]=-74197,["x"]=-360556.57142855,}, - [3]={["y"]=-74402.714285715,["x"]=-359639.42857141,}, - [4]={["y"]=-74637,["x"]=-359279.42857141,}, - [5]={["y"]=-75759.857142857,["x"]=-359005.14285712,}, - [6]={["y"]=-75834.142857143,["x"]=-359045.14285712,}, - [7]={["y"]=-75902.714285714,["x"]=-359782.28571427,}, - [8]={["y"]=-76099.857142857,["x"]=-360399.42857141,}, - [9]={["y"]=-77314.142857143,["x"]=-360219.42857141,}, - [10]={["y"]=-77728.428571429,["x"]=-360445.14285713,}, - [11]={["y"]=-77585.571428571,["x"]=-360585.14285713,}, - [12]={["y"]=-76471.285714286,["x"]=-360819.42857141,}, - [13]={["y"]=-76325.571428571,["x"]=-360942.28571427,}, - [14]={["y"]=-74671.857142857,["x"]=-360927.7142857,}, - [15]={["y"]=-74522.714285714,["x"]=-360888.85714284,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-74237.571428571,["x"]=-360591.7142857,}, - [2]={["y"]=-74234.428571429,["x"]=-360493.71428571,}, - [3]={["y"]=-77605.285714286,["x"]=-360399.14285713,}, - [4]={["y"]=-77608.714285715,["x"]=-360498.85714285,}, - [5]={["y"]=-74237.857142857,["x"]=-360591.7142857,}, - }, - [2] = { - [1]={["y"]=-75807.571428572,["x"]=-359073.42857142,}, - [2]={["y"]=-74770.142857144,["x"]=-360581.71428571,}, - [3]={["y"]=-74641.285714287,["x"]=-360585.42857142,}, - [4]={["y"]=-75734.142857144,["x"]=-359023.14285714,}, - [5]={["y"]=-75807.285714287,["x"]=-359073.42857142,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - GroomLake = { - PointsBoundary = { - [1]={["y"]=-88916.714285714,["x"]=-289102.28571425,}, - [2]={["y"]=-87023.571428572,["x"]=-290388.57142857,}, - [3]={["y"]=-85916.428571429,["x"]=-290674.28571428,}, - [4]={["y"]=-87645.000000001,["x"]=-286567.14285714,}, - [5]={["y"]=-88380.714285715,["x"]=-286388.57142857,}, - [6]={["y"]=-89670.714285715,["x"]=-283524.28571428,}, - [7]={["y"]=-89797.857142858,["x"]=-283567.14285714,}, - [8]={["y"]=-88635.000000001,["x"]=-286749.99999999,}, - [9]={["y"]=-89177.857142858,["x"]=-287207.14285714,}, - [10]={["y"]=-89092.142857144,["x"]=-288892.85714285,}, - [11]={["y"]=-88917.000000001,["x"]=-289102.85714285,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-86039.000000001,["x"]=-290606.28571428,}, - [2]={["y"]=-85965.285714287,["x"]=-290573.99999999,}, - [3]={["y"]=-87692.714285715,["x"]=-286634.85714285,}, - [4]={["y"]=-87756.714285715,["x"]=-286663.99999999,}, - [5]={["y"]=-86038.714285715,["x"]=-290606.85714285,}, - }, - [2] = { - [1]={["y"]=-86808.428571429,["x"]=-290375.7142857,}, - [2]={["y"]=-86732.714285715,["x"]=-290344.28571427,}, - [3]={["y"]=-89672.714285714,["x"]=-283546.57142855,}, - [4]={["y"]=-89772.142857143,["x"]=-283587.71428569,}, - [5]={["y"]=-86808.142857143,["x"]=-290375.7142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - }, -} - ---- Creates a new AIRBASEPOLICE_NEVADA object. --- @param #AIRBASEPOLICE_NEVADA self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @return #AIRBASEPOLICE_NEVADA self -function AIRBASEPOLICE_NEVADA:New( SetClient ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) - --- -- Nellis --- local NellisBoundary = GROUP:FindByName( "Nellis Boundary" ) --- self.Airbases.Nellis.ZoneBoundary = ZONE_POLYGON:New( "Nellis Boundary", NellisBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local NellisRunway1 = GROUP:FindByName( "Nellis Runway 1" ) --- self.Airbases.Nellis.ZoneRunways[1] = ZONE_POLYGON:New( "Nellis Runway 1", NellisRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local NellisRunway2 = GROUP:FindByName( "Nellis Runway 2" ) --- self.Airbases.Nellis.ZoneRunways[2] = ZONE_POLYGON:New( "Nellis Runway 2", NellisRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- McCarran --- local McCarranBoundary = GROUP:FindByName( "McCarran Boundary" ) --- self.Airbases.McCarran.ZoneBoundary = ZONE_POLYGON:New( "McCarran Boundary", McCarranBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local McCarranRunway1 = GROUP:FindByName( "McCarran Runway 1" ) --- self.Airbases.McCarran.ZoneRunways[1] = ZONE_POLYGON:New( "McCarran Runway 1", McCarranRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway2 = GROUP:FindByName( "McCarran Runway 2" ) --- self.Airbases.McCarran.ZoneRunways[2] = ZONE_POLYGON:New( "McCarran Runway 2", McCarranRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway3 = GROUP:FindByName( "McCarran Runway 3" ) --- self.Airbases.McCarran.ZoneRunways[3] = ZONE_POLYGON:New( "McCarran Runway 3", McCarranRunway3 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway4 = GROUP:FindByName( "McCarran Runway 4" ) --- self.Airbases.McCarran.ZoneRunways[4] = ZONE_POLYGON:New( "McCarran Runway 4", McCarranRunway4 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- Creech --- local CreechBoundary = GROUP:FindByName( "Creech Boundary" ) --- self.Airbases.Creech.ZoneBoundary = ZONE_POLYGON:New( "Creech Boundary", CreechBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local CreechRunway1 = GROUP:FindByName( "Creech Runway 1" ) --- self.Airbases.Creech.ZoneRunways[1] = ZONE_POLYGON:New( "Creech Runway 1", CreechRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local CreechRunway2 = GROUP:FindByName( "Creech Runway 2" ) --- self.Airbases.Creech.ZoneRunways[2] = ZONE_POLYGON:New( "Creech Runway 2", CreechRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- Groom Lake --- local GroomLakeBoundary = GROUP:FindByName( "GroomLake Boundary" ) --- self.Airbases.GroomLake.ZoneBoundary = ZONE_POLYGON:New( "GroomLake Boundary", GroomLakeBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local GroomLakeRunway1 = GROUP:FindByName( "GroomLake Runway 1" ) --- self.Airbases.GroomLake.ZoneRunways[1] = ZONE_POLYGON:New( "GroomLake Runway 1", GroomLakeRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local GroomLakeRunway2 = GROUP:FindByName( "GroomLake Runway 2" ) --- self.Airbases.GroomLake.ZoneRunways[2] = ZONE_POLYGON:New( "GroomLake Runway 2", GroomLakeRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -end - - - - - - --- This module contains the DETECTION classes. --- --- === --- --- 1) @{Functional.Detection#DETECTION_BASE} class, extends @{Core.Base#BASE} --- ========================================================== --- The @{Functional.Detection#DETECTION_BASE} class defines the core functions to administer detected objects. --- The @{Functional.Detection#DETECTION_BASE} class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s). --- --- 1.1) DETECTION_BASE constructor --- ------------------------------- --- Construct a new DETECTION_BASE instance using the @{Functional.Detection#DETECTION_BASE.New}() method. --- --- 1.2) DETECTION_BASE initialization --- ---------------------------------- --- By default, detection will return detected objects with all the detection sensors available. --- However, you can ask how the objects were found with specific detection methods. --- If you use one of the below methods, the detection will work with the detection method specified. --- You can specify to apply multiple detection methods. --- --- Use the following functions to report the objects it detected using the methods Visual, Optical, Radar, IRST, RWR, DLINK: --- --- * @{Functional.Detection#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. --- * @{Functional.Detection#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. --- * @{Functional.Detection#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. --- * @{Functional.Detection#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. --- * @{Functional.Detection#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. --- * @{Functional.Detection#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. --- --- 1.3) Obtain objects detected by DETECTION_BASE --- ---------------------------------------------- --- DETECTION_BASE builds @{Set}s of objects detected. These @{Core.Set#SET_BASE}s can be retrieved using the method @{Functional.Detection#DETECTION_BASE.GetDetectedSets}(). --- The method will return a list (table) of @{Core.Set#SET_BASE} objects. --- --- === --- --- 2) @{Functional.Detection#DETECTION_AREAS} class, extends @{Functional.Detection#DETECTION_BASE} --- =============================================================================== --- The @{Functional.Detection#DETECTION_AREAS} class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s), --- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Wrapper.Unit#UNIT}s detected. --- The class is group the detected units within zones given a DetectedZoneRange parameter. --- A set with multiple detected zones will be created as there are groups of units detected. --- --- 2.1) Retrieve the Detected Unit sets and Detected Zones --- ------------------------------------------------------- --- The DetectedUnitSets methods are implemented in @{Functional.Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Functional.Detection#DETECTION_AREAS}. --- --- Retrieve the DetectedUnitSets with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Core.Set#SET_UNIT}s. --- To understand the amount of sets created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectedSetCount}(). --- If you want to obtain a specific set from the DetectedSets, use the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}() with a given index. --- --- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}(). --- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}(). --- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index. --- --- 1.4) Flare or Smoke detected units --- ---------------------------------- --- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place. --- --- 1.5) Flare or Smoke detected zones --- ---------------------------------- --- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedZones}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place. --- --- === --- --- ### Contributions: --- --- * Mechanist : Concept & Testing --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- @module Detection - - - ---- DETECTION_BASE class --- @type DETECTION_BASE --- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. --- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. --- @field #number DetectionRun --- @extends Core.Base#BASE -DETECTION_BASE = { - ClassName = "DETECTION_BASE", - DetectionSetGroup = nil, - DetectionRange = nil, - DetectedObjects = {}, - DetectionRun = 0, - DetectedObjectsIdentified = {}, -} - ---- @type DETECTION_BASE.DetectedObjects --- @list <#DETECTION_BASE.DetectedObject> - ---- @type DETECTION_BASE.DetectedObject --- @field #string Name --- @field #boolean Visible --- @field #string Type --- @field #number Distance --- @field #boolean Identified - ---- DETECTION constructor. --- @param #DETECTION_BASE self --- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @param Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @return #DETECTION_BASE self -function DETECTION_BASE:New( DetectionSetGroup, DetectionRange ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - self.DetectionSetGroup = DetectionSetGroup - self.DetectionRange = DetectionRange - - self:InitDetectVisual( false ) - self:InitDetectOptical( false ) - self:InitDetectRadar( false ) - self:InitDetectRWR( false ) - self:InitDetectIRST( false ) - self:InitDetectDLINK( false ) - - return self -end - ---- Detect Visual. --- @param #DETECTION_BASE self --- @param #boolean DetectVisual --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectVisual( DetectVisual ) - - self.DetectVisual = DetectVisual -end - ---- Detect Optical. --- @param #DETECTION_BASE self --- @param #boolean DetectOptical --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectOptical( DetectOptical ) - self:F2() - - self.DetectOptical = DetectOptical -end - ---- Detect Radar. --- @param #DETECTION_BASE self --- @param #boolean DetectRadar --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectRadar( DetectRadar ) - self:F2() - - self.DetectRadar = DetectRadar -end - ---- Detect IRST. --- @param #DETECTION_BASE self --- @param #boolean DetectIRST --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectIRST( DetectIRST ) - self:F2() - - self.DetectIRST = DetectIRST -end - ---- Detect RWR. --- @param #DETECTION_BASE self --- @param #boolean DetectRWR --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectRWR( DetectRWR ) - self:F2() - - self.DetectRWR = DetectRWR -end - ---- Detect DLINK. --- @param #DETECTION_BASE self --- @param #boolean DetectDLINK --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectDLINK( DetectDLINK ) - self:F2() - - self.DetectDLINK = DetectDLINK -end - ---- Determines if a detected object has already been identified during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject --- @return #boolean true if already identified. -function DETECTION_BASE:IsDetectedObjectIdentified( DetectedObject ) - self:F3( DetectedObject.Name ) - - local DetectedObjectName = DetectedObject.Name - local DetectedObjectIdentified = self.DetectedObjectsIdentified[DetectedObjectName] == true - self:T3( DetectedObjectIdentified ) - return DetectedObjectIdentified -end - ---- Identifies a detected object during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject -function DETECTION_BASE:IdentifyDetectedObject( DetectedObject ) - self:F( DetectedObject.Name ) - - local DetectedObjectName = DetectedObject.Name - self.DetectedObjectsIdentified[DetectedObjectName] = true -end - ---- UnIdentify a detected object during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject -function DETECTION_BASE:UnIdentifyDetectedObject( DetectedObject ) - - local DetectedObjectName = DetectedObject.Name - self.DetectedObjectsIdentified[DetectedObjectName] = false -end - ---- UnIdentify all detected objects during detection processing. --- @param #DETECTION_BASE self -function DETECTION_BASE:UnIdentifyAllDetectedObjects() - - self.DetectedObjectsIdentified = {} -- Table will be garbage collected. -end - ---- Gets a detected object with a given name. --- @param #DETECTION_BASE self --- @param #string ObjectName --- @return #DETECTION_BASE.DetectedObject -function DETECTION_BASE:GetDetectedObject( ObjectName ) - self:F3( ObjectName ) - - if ObjectName then - local DetectedObject = self.DetectedObjects[ObjectName] - - -- Only return detected objects that are alive! - local DetectedUnit = UNIT:FindByName( ObjectName ) - if DetectedUnit and DetectedUnit:IsAlive() then - if self:IsDetectedObjectIdentified( DetectedObject ) == false then - return DetectedObject - end - end - end - - return nil -end - ---- Get the detected @{Core.Set#SET_BASE}s. --- @param #DETECTION_BASE self --- @return #DETECTION_BASE.DetectedSets DetectedSets -function DETECTION_BASE:GetDetectedSets() - - local DetectionSets = self.DetectedSets - return DetectionSets -end - ---- Get the amount of SETs with detected objects. --- @param #DETECTION_BASE self --- @return #number Count -function DETECTION_BASE:GetDetectedSetCount() - - local DetectionSetCount = #self.DetectedSets - return DetectionSetCount -end - ---- Get a SET of detected objects using a given numeric index. --- @param #DETECTION_BASE self --- @param #number Index --- @return Core.Set#SET_BASE -function DETECTION_BASE:GetDetectedSet( Index ) - - local DetectionSet = self.DetectedSets[Index] - if DetectionSet then - return DetectionSet - end - - return nil -end - ---- Get the detection Groups. --- @param #DETECTION_BASE self --- @return Wrapper.Group#GROUP -function DETECTION_BASE:GetDetectionSetGroup() - - local DetectionSetGroup = self.DetectionSetGroup - return DetectionSetGroup -end - ---- Make a DetectionSet table. This function will be overridden in the derived clsses. --- @param #DETECTION_BASE self --- @return #DETECTION_BASE self -function DETECTION_BASE:CreateDetectionSets() - self:F2() - - self:E( "Error, in DETECTION_BASE class..." ) - -end - - ---- Schedule the DETECTION construction. --- @param #DETECTION_BASE self --- @param #number DelayTime The delay in seconds to wait the reporting. --- @param #number RepeatInterval The repeat interval in seconds for the reporting to happen repeatedly. --- @return #DETECTION_BASE self -function DETECTION_BASE:Schedule( DelayTime, RepeatInterval ) - self:F2() - - self.ScheduleDelayTime = DelayTime - self.ScheduleRepeatInterval = RepeatInterval - - self.DetectionScheduler = SCHEDULER:New(self, self._DetectionScheduler, { self, "Detection" }, DelayTime, RepeatInterval ) - return self -end - - ---- Form @{Set}s of detected @{Wrapper.Unit#UNIT}s in an array of @{Core.Set#SET_BASE}s. --- @param #DETECTION_BASE self -function DETECTION_BASE:_DetectionScheduler( SchedulerName ) - self:F2( { SchedulerName } ) - - self.DetectionRun = self.DetectionRun + 1 - - self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table - - for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do - local DetectionGroup = DetectionGroupData -- Wrapper.Group#GROUP - - if DetectionGroup:IsAlive() then - - local DetectionGroupName = DetectionGroup:GetName() - - local DetectionDetectedTargets = DetectionGroup:GetDetectedTargets( - self.DetectVisual, - self.DetectOptical, - self.DetectRadar, - self.DetectIRST, - self.DetectRWR, - self.DetectDLINK - ) - - for DetectionDetectedTargetID, DetectionDetectedTarget in pairs( DetectionDetectedTargets ) do - local DetectionObject = DetectionDetectedTarget.object -- Dcs.DCSWrapper.Object#Object - self:T2( DetectionObject ) - - if DetectionObject and DetectionObject:isExist() and DetectionObject.id_ < 50000000 then - - local DetectionDetectedObjectName = DetectionObject:getName() - - local DetectionDetectedObjectPositionVec3 = DetectionObject:getPoint() - local DetectionGroupVec3 = DetectionGroup:GetVec3() - - local Distance = ( ( DetectionDetectedObjectPositionVec3.x - DetectionGroupVec3.x )^2 + - ( DetectionDetectedObjectPositionVec3.y - DetectionGroupVec3.y )^2 + - ( DetectionDetectedObjectPositionVec3.z - DetectionGroupVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T2( { DetectionGroupName, DetectionDetectedObjectName, Distance } ) - - if Distance <= self.DetectionRange then - - if not self.DetectedObjects[DetectionDetectedObjectName] then - self.DetectedObjects[DetectionDetectedObjectName] = {} - end - self.DetectedObjects[DetectionDetectedObjectName].Name = DetectionDetectedObjectName - self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible - self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type - self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance - else - -- if beyond the DetectionRange then nullify... - if self.DetectedObjects[DetectionDetectedObjectName] then - self.DetectedObjects[DetectionDetectedObjectName] = nil - end - end - end - end - - self:T2( self.DetectedObjects ) - - -- okay, now we have a list of detected object names ... - -- Sort the table based on distance ... - table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end ) - end - end - - if self.DetectedObjects then - self:CreateDetectionSets() - end - - return true -end - - - ---- DETECTION_AREAS class --- @type DETECTION_AREAS --- @field Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @field #DETECTION_AREAS.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. --- @extends Functional.Detection#DETECTION_BASE -DETECTION_AREAS = { - ClassName = "DETECTION_AREAS", - DetectedAreas = { n = 0 }, - DetectionZoneRange = nil, -} - ---- @type DETECTION_AREAS.DetectedAreas --- @list <#DETECTION_AREAS.DetectedArea> - ---- @type DETECTION_AREAS.DetectedArea --- @field Core.Set#SET_UNIT Set -- The Set of Units in the detected area. --- @field Core.Zone#ZONE_UNIT Zone -- The Zone of the detected area. --- @field #boolean Changed Documents if the detected area has changes. --- @field #table Changes A list of the changes reported on the detected area. (It is up to the user of the detected area to consume those changes). --- @field #number AreaID -- The identifier of the detected area. --- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area. --- @field Wrapper.Unit#UNIT NearestFAC The nearest FAC near the Area. - - ---- DETECTION_AREAS constructor. --- @param Functional.Detection#DETECTION_AREAS self --- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @param Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @param Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @return Functional.Detection#DETECTION_AREAS self -function DETECTION_AREAS:New( DetectionSetGroup, DetectionRange, DetectionZoneRange ) - - -- Inherits from DETECTION_BASE - local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup, DetectionRange ) ) - - self.DetectionZoneRange = DetectionZoneRange - - self._SmokeDetectedUnits = false - self._FlareDetectedUnits = false - self._SmokeDetectedZones = false - self._FlareDetectedZones = false - - self:Schedule( 0, 30 ) - - return self -end - ---- Add a detected @{#DETECTION_AREAS.DetectedArea}. --- @param Core.Set#SET_UNIT Set -- The Set of Units in the detected area. --- @param Core.Zone#ZONE_UNIT Zone -- The Zone of the detected area. --- @return #DETECTION_AREAS.DetectedArea DetectedArea -function DETECTION_AREAS:AddDetectedArea( Set, Zone ) - local DetectedAreas = self:GetDetectedAreas() - DetectedAreas.n = self:GetDetectedAreaCount() + 1 - DetectedAreas[DetectedAreas.n] = {} - local DetectedArea = DetectedAreas[DetectedAreas.n] - DetectedArea.Set = Set - DetectedArea.Zone = Zone - DetectedArea.Removed = false - DetectedArea.AreaID = DetectedAreas.n - - return DetectedArea -end - ---- Remove a detected @{#DETECTION_AREAS.DetectedArea} with a given Index. --- @param #DETECTION_AREAS self --- @param #number Index The Index of the detection are to be removed. --- @return #nil -function DETECTION_AREAS:RemoveDetectedArea( Index ) - local DetectedAreas = self:GetDetectedAreas() - local DetectedAreaCount = self:GetDetectedAreaCount() - local DetectedArea = DetectedAreas[Index] - local DetectedAreaSet = DetectedArea.Set - DetectedArea[Index] = nil - return nil -end - - ---- Get the detected @{#DETECTION_AREAS.DetectedAreas}. --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS.DetectedAreas DetectedAreas -function DETECTION_AREAS:GetDetectedAreas() - - local DetectedAreas = self.DetectedAreas - return DetectedAreas -end - ---- Get the amount of @{#DETECTION_AREAS.DetectedAreas}. --- @param #DETECTION_AREAS self --- @return #number DetectedAreaCount -function DETECTION_AREAS:GetDetectedAreaCount() - - local DetectedAreaCount = self.DetectedAreas.n - return DetectedAreaCount -end - ---- Get the @{Core.Set#SET_UNIT} of a detecttion area using a given numeric index. --- @param #DETECTION_AREAS self --- @param #number Index --- @return Core.Set#SET_UNIT DetectedSet -function DETECTION_AREAS:GetDetectedSet( Index ) - - local DetectedSetUnit = self.DetectedAreas[Index].Set - if DetectedSetUnit then - return DetectedSetUnit - end - - return nil -end - ---- Get the @{Core.Zone#ZONE_UNIT} of a detection area using a given numeric index. --- @param #DETECTION_AREAS self --- @param #number Index --- @return Core.Zone#ZONE_UNIT DetectedZone -function DETECTION_AREAS:GetDetectedZone( Index ) - - local DetectedZone = self.DetectedAreas[Index].Zone - if DetectedZone then - return DetectedZone - end - - return nil -end - ---- Background worker function to determine if there are friendlies nearby ... --- @param #DETECTION_AREAS self --- @param Wrapper.Unit#UNIT ReportUnit -function DETECTION_AREAS:ReportFriendliesNearBy( ReportGroupData ) - self:F2() - - local DetectedArea = ReportGroupData.DetectedArea -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = ReportGroupData.DetectedArea.Set - local DetectedZone = ReportGroupData.DetectedArea.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT - - DetectedArea.FriendliesNearBy = false - - local SphereSearch = { - id = world.VolumeType.SPHERE, - params = { - point = DetectedZoneUnit:GetVec3(), - radius = 6000, - } - - } - - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit - -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup - local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) - - local DetectedArea = ReportGroupData.DetectedArea -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = ReportGroupData.DetectedArea.Set - local DetectedZone = ReportGroupData.DetectedArea.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT -- Wrapper.Unit#UNIT - local ReportSetGroup = ReportGroupData.ReportSetGroup - - local EnemyCoalition = DetectedZoneUnit:GetCoalition() - - local FoundUnitCoalition = FoundDCSUnit:getCoalition() - local FoundUnitName = FoundDCSUnit:getName() - local FoundUnitGroupName = FoundDCSUnit:getGroup():getName() - local EnemyUnitName = DetectedZoneUnit:GetName() - local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil - - self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) - - if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then - DetectedArea.FriendliesNearBy = true - return false - end - - return true - end - - world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData ) - -end - - - ---- Returns if there are friendlies nearby the FAC units ... --- @param #DETECTION_AREAS self --- @return #boolean trhe if there are friendlies nearby -function DETECTION_AREAS:IsFriendliesNearBy( DetectedArea ) - - self:T3( DetectedArea.FriendliesNearBy ) - return DetectedArea.FriendliesNearBy or false -end - ---- Calculate the maxium A2G threat level of the DetectedArea. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea -function DETECTION_AREAS:CalculateThreatLevelA2G( DetectedArea ) - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( DetectedArea.Set:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - DetectedArea.MaxThreatLevelA2G = MaxThreatLevelA2G - -end - ---- Find the nearest FAC of the DetectedArea. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return Wrapper.Unit#UNIT The nearest FAC unit -function DETECTION_AREAS:NearestFAC( DetectedArea ) - - local NearestFAC = nil - local MinDistance = 1000000000 -- Units are not further than 1000000 km away from an area :-) - - for FACGroupName, FACGroupData in pairs( self.DetectionSetGroup:GetSet() ) do - for FACUnit, FACUnitData in pairs( FACGroupData:GetUnits() ) do - local FACUnit = FACUnitData -- Wrapper.Unit#UNIT - if FACUnit:IsActive() then - local Vec3 = FACUnit:GetVec3() - local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) - local Distance = PointVec3:Get2DDistance(POINT_VEC3:NewFromVec3( FACUnit:GetVec3() ) ) - if Distance < MinDistance then - MinDistance = Distance - NearestFAC = FACUnit - end - end - end - end - - DetectedArea.NearestFAC = NearestFAC - -end - ---- Returns the A2G threat level of the units in the DetectedArea --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #number a scale from 0 to 10. -function DETECTION_AREAS:GetTreatLevelA2G( DetectedArea ) - - self:T3( DetectedArea.MaxThreatLevelA2G ) - return DetectedArea.MaxThreatLevelA2G -end - - - ---- Smoke the detected units --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:SmokeDetectedUnits() - self:F2() - - self._SmokeDetectedUnits = true - return self -end - ---- Flare the detected units --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:FlareDetectedUnits() - self:F2() - - self._FlareDetectedUnits = true - return self -end - ---- Smoke the detected zones --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:SmokeDetectedZones() - self:F2() - - self._SmokeDetectedZones = true - return self -end - ---- Flare the detected zones --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:FlareDetectedZones() - self:F2() - - self._FlareDetectedZones = true - return self -end - ---- Add a change to the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @param #string ChangeCode --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AddChangeArea( DetectedArea, ChangeCode, AreaUnitType ) - - DetectedArea.Changed = true - local AreaID = DetectedArea.AreaID - - DetectedArea.Changes = DetectedArea.Changes or {} - DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {} - DetectedArea.Changes[ChangeCode].AreaID = AreaID - DetectedArea.Changes[ChangeCode].AreaUnitType = AreaUnitType - - self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, AreaUnitType } ) - - return self -end - - ---- Add a change to the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @param #string ChangeCode --- @param #string ChangeUnitType --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AddChangeUnit( DetectedArea, ChangeCode, ChangeUnitType ) - - DetectedArea.Changed = true - local AreaID = DetectedArea.AreaID - - DetectedArea.Changes = DetectedArea.Changes or {} - DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {} - DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] or 0 - DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] + 1 - DetectedArea.Changes[ChangeCode].AreaID = AreaID - - self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, ChangeUnitType } ) - - return self -end - ---- Make text documenting the changes of the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #string The Changes text -function DETECTION_AREAS:GetChangeText( DetectedArea ) - self:F( DetectedArea ) - - local MT = {} - - for ChangeCode, ChangeData in pairs( DetectedArea.Changes ) do - - if ChangeCode == "AA" then - MT[#MT+1] = "Detected new area " .. ChangeData.AreaID .. ". The center target is a " .. ChangeData.AreaUnitType .. "." - end - - if ChangeCode == "RAU" then - MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". Removed the center target." - end - - if ChangeCode == "AAU" then - MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". The new center target is a " .. ChangeData.AreaUnitType "." - end - - if ChangeCode == "RA" then - MT[#MT+1] = "Removed old area " .. ChangeData.AreaID .. ". No more targets in this area." - end - - if ChangeCode == "AU" then - local MTUT = {} - for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do - if ChangeUnitType ~= "AreaID" then - MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType - end - end - MT[#MT+1] = "Detected for area " .. ChangeData.AreaID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "." - end - - if ChangeCode == "RU" then - local MTUT = {} - for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do - if ChangeUnitType ~= "AreaID" then - MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType - end - end - MT[#MT+1] = "Removed for area " .. ChangeData.AreaID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "." - end - - end - - return table.concat( MT, "\n" ) - -end - - ---- Accepts changes from the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AcceptChanges( DetectedArea ) - - DetectedArea.Changed = false - DetectedArea.Changes = {} - - return self -end - - ---- Make a DetectionSet table. This function will be overridden in the derived clsses. --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:CreateDetectionSets() - self:F2() - - -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. - -- Regroup when needed, split groups when needed. - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - if DetectedArea then - - local DetectedSet = DetectedArea.Set - - local AreaExists = false -- This flag will determine of the detected area is still existing. - - -- First test if the center unit is detected in the detection area. - self:T3( DetectedArea.Zone.ZoneUNIT.UnitName ) - local DetectedZoneObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName ) - self:T3( { "Detecting Zone Object", DetectedArea.AreaID, DetectedArea.Zone, DetectedZoneObject } ) - - if DetectedZoneObject then - - --self:IdentifyDetectedObject( DetectedZoneObject ) - AreaExists = true - - - - else - -- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area. - -- First remove the center unit from the set. - DetectedSet:RemoveUnitsByName( DetectedArea.Zone.ZoneUNIT.UnitName ) - - self:AddChangeArea( DetectedArea, 'RAU', "Dummy" ) - - -- Then search for a new center area unit within the set. Note that the new area unit candidate must be within the area range. - for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName ) - - -- The DetectedObject can be nil when the DetectedUnit is not alive anymore or it is not in the DetectedObjects map. - -- If the DetectedUnit was already identified, DetectedObject will be nil. - if DetectedObject then - self:IdentifyDetectedObject( DetectedObject ) - AreaExists = true - - -- Assign the Unit as the new center unit of the detected area. - DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange ) - - self:AddChangeArea( DetectedArea, "AAU", DetectedArea.Zone.ZoneUNIT:GetTypeName() ) - - -- We don't need to add the DetectedObject to the area set, because it is already there ... - break - end - end - end - - -- Now we've determined the center unit of the area, now we can iterate the units in the detected area. - -- Note that the position of the area may have moved due to the center unit repositioning. - -- If no center unit was identified, then the detected area does not exist anymore and should be deleted, as there are no valid units that can be the center unit. - if AreaExists then - - -- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ... - -- Those units within the zone are flagged as Identified. - -- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets. - for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - local DetectedObject = nil - if DetectedUnit:IsAlive() then - --self:E(DetectedUnit:GetName()) - DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) - end - if DetectedObject then - - -- Check if the DetectedUnit is within the DetectedArea.Zone - if DetectedUnit:IsInZone( DetectedArea.Zone ) then - - -- Yes, the DetectedUnit is within the DetectedArea.Zone, no changes, DetectedUnit can be kept within the Set. - self:IdentifyDetectedObject( DetectedObject ) - - else - -- No, the DetectedUnit is not within the DetectedArea.Zone, remove DetectedUnit from the Set. - DetectedSet:Remove( DetectedUnitName ) - self:AddChangeUnit( DetectedArea, "RU", DetectedUnit:GetTypeName() ) - end - - else - -- There was no DetectedObject, remove DetectedUnit from the Set. - self:AddChangeUnit( DetectedArea, "RU", "destroyed target" ) - DetectedSet:Remove( DetectedUnitName ) - - -- The DetectedObject has been identified, because it does not exist ... - -- self:IdentifyDetectedObject( DetectedObject ) - end - end - else - self:RemoveDetectedArea( DetectedAreaID ) - self:AddChangeArea( DetectedArea, "RA" ) - end - end - end - - -- We iterated through the existing detection areas and: - -- - We checked which units are still detected in each detection area. Those units were flagged as Identified. - -- - We recentered the detection area to new center units where it was needed. - -- - -- Now we need to loop through the unidentified detected units and see where they belong: - -- - They can be added to a new detection area and become the new center unit. - -- - They can be added to a new detection area. - for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do - - local DetectedObject = self:GetDetectedObject( DetectedUnitName ) - - if DetectedObject then - - -- We found an unidentified unit outside of any existing detection area. - local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT - - local AddedToDetectionArea = false - - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - if DetectedArea then - self:T( "Detection Area #" .. DetectedArea.AreaID ) - local DetectedSet = DetectedArea.Set - if not self:IsDetectedObjectIdentified( DetectedObject ) and DetectedUnit:IsInZone( DetectedArea.Zone ) then - self:IdentifyDetectedObject( DetectedObject ) - DetectedSet:AddUnit( DetectedUnit ) - AddedToDetectionArea = true - self:AddChangeUnit( DetectedArea, "AU", DetectedUnit:GetTypeName() ) - end - end - end - - if AddedToDetectionArea == false then - - -- New detection area - local DetectedArea = self:AddDetectedArea( - SET_UNIT:New(), - ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - ) - --self:E( DetectedArea.Zone.ZoneUNIT.UnitName ) - DetectedArea.Set:AddUnit( DetectedUnit ) - self:AddChangeArea( DetectedArea, "AA", DetectedUnit:GetTypeName() ) - end - end - end - - -- Now all the tests should have been build, now make some smoke and flares... - -- We also report here the friendlies within the detected areas. - - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - self:ReportFriendliesNearBy( { DetectedArea = DetectedArea, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table - self:CalculateThreatLevelA2G( DetectedArea ) -- Calculate A2G threat level - self:NearestFAC( DetectedArea ) - - if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then - DetectedZone.ZoneUNIT:SmokeRed() - end - DetectedSet:ForEachUnit( - --- @param Wrapper.Unit#UNIT DetectedUnit - function( DetectedUnit ) - if DetectedUnit:IsAlive() then - self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() ) - if DETECTION_AREAS._FlareDetectedUnits or self._FlareDetectedUnits then - DetectedUnit:FlareGreen() - end - if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then - DetectedUnit:SmokeGreen() - end - end - end - ) - if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then - DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) ) - end - if DETECTION_AREAS._SmokeDetectedZones or self._SmokeDetectedZones then - DetectedZone:SmokeZone( SMOKECOLOR.White, 30 ) - end - end - -end - - ---- SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class. AI Balancing will replace in multi player missions --- non-occupied human slots with AI groups, in order to provide an engaging simulation environment, --- even when there are hardly any players in the mission. --- --- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) --- --- Examples can be found in the test missions. --- --- === --- --- # 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} --- --- The @{AI.AI_Balancer#AI_BALANCER} class monitors and manages as many replacement AI groups as there are --- CLIENTS in a SET_CLIENT collection, which are not occupied by human players. --- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. --- --- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). --- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods. --- An explanation about state and event transition methods can be found in the @{FSM} module documentation. --- --- The mission designer can tailor the AI_BALANCER behaviour, by implementing a state or event handling method for the following: --- --- * **@{#AI_BALANCER.OnAfterSpawned}**( AISet, From, Event, To, AIGroup ): Define to add extra logic when an AI is spawned. --- --- ## 1.1) AI_BALANCER construction --- --- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: --- --- ## 1.2) AI_BALANCER is a FSM --- --- ![Process](..\Presentations\AI_Balancer\Dia13.JPG) --- --- ### 1.2.1) AI_BALANCER States --- --- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. --- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. --- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. --- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. --- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. --- --- ### 1.2.2) AI_BALANCER Events --- --- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. --- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. --- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. --- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. --- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. --- --- ## 1.3) AI_BALANCER spawn interval for replacement AI --- --- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. --- --- ## 1.4) AI_BALANCER returns AI to Airbases --- --- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. --- However, there are 2 additional options that you can use to customize the destroy behaviour. --- When a human player joins a slot, you can configure to let the AI return to: --- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. --- --- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return, --- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed. --- --- === --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) --- --- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. --- --- ### Authors: --- --- * FlightControl: Framework Design & Programming and Documentation. --- --- @module AI_Balancer - ---- AI_BALANCER class --- @type AI_BALANCER --- @field Core.Set#SET_CLIENT SetClient --- @field Functional.Spawn#SPAWN SpawnAI --- @field Wrapper.Group#GROUP Test --- @extends Core.Fsm#FSM_SET -AI_BALANCER = { - ClassName = "AI_BALANCER", - PatrolZones = {}, - AIGroups = {}, - Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. - Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. -} - - - ---- Creates a new AI_BALANCER object --- @param #AI_BALANCER self --- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). --- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. --- @return #AI_BALANCER -function AI_BALANCER:New( SetClient, SpawnAI ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER - - self:SetStartState( "None" ) - self:AddTransition( "*", "Monitor", "Monitoring" ) - self:AddTransition( "*", "Spawn", "Spawning" ) - self:AddTransition( "Spawning", "Spawned", "Spawned" ) - self:AddTransition( "*", "Destroy", "Destroying" ) - self:AddTransition( "*", "Return", "Returning" ) - - self.SetClient = SetClient - self.SetClient:FilterOnce() - self.SpawnAI = SpawnAI - - self.SpawnQueue = {} - - self.ToNearestAirbase = false - self.ToHomeAirbase = false - - self:__Monitor( 1 ) - - return self -end - ---- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. --- Provide 2 identical seconds if the interval should be a fixed amount of seconds. --- @param #AI_BALANCER self --- @param #number Earliest The earliest a new AI can be spawned in seconds. --- @param #number Latest The latest a new AI can be spawned in seconds. --- @return self -function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) - - self.Earliest = Earliest - self.Latest = Latest - - return self -end - ---- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. --- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. --- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to. -function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) - - self.ToNearestAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange - self.ReturnAirbaseSet = ReturnAirbaseSet -end - ---- Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. --- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. -function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) - - self.ToHomeAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param #string ClientName --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) - - -- OK, Spawn a new group from the default SpawnAI object provided. - local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP - AIGroup:E( "Spawning new AIGroup" ) - --TODO: need to rework UnitName thing ... - - SetGroup:Add( ClientName, AIGroup ) - self.SpawnQueue[ClientName] = nil - - -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. - -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) - - AIGroup:Destroy() - SetGroup:Flush() - SetGroup:Remove( ClientName ) - SetGroup:Flush() -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup ) - - local AIGroupTemplate = AIGroup:GetTemplate() - if self.ToHomeAirbase == true then - local WayPointCount = #AIGroupTemplate.route.points - local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) - AIGroup:SetCommand( SwitchWayPointCommand ) - AIGroup:MessageToRed( "Returning to home base ...", 30 ) - else - -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. - --TODO: i need to rework the POINT_VEC2 thing. - local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) - local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) - self:T( ClosestAirbase.AirbaseName ) - AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) - local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) - AIGroupTemplate.route = RTBRoute - AIGroup:Respawn( AIGroupTemplate ) - end - -end - - ---- @param #AI_BALANCER self -function AI_BALANCER:onenterMonitoring( SetGroup ) - - self:E( { self.SetClient:Count() } ) - self.SetClient:Flush() - - self.SetClient:ForEachClient( - --- @param Wrapper.Client#CLIENT Client - function( Client ) - self:E(Client.ClientName) - - local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP - self:E({Client:IsAlive()}) - if Client:IsAlive() then - - if AIGroup and AIGroup:IsAlive() == true then - - if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - self:Destroy( Client.UnitName, AIGroup ) - else - -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. - -- If there is a CLIENT, the AI stays engaged and will not return. - -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. - - local PlayerInRange = { Value = false } - local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) - - self:E( RangeZone ) - - _DATABASE:ForEachPlayer( - --- @param Wrapper.Unit#UNIT RangeTestUnit - function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) - self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) - if RangeTestUnit:IsInZone( RangeZone ) == true then - self:E( "in zone" ) - if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then - self:E( "in range" ) - PlayerInRange.Value = true - end - end - end, - - --- @param Core.Zone#ZONE_RADIUS RangeZone - -- @param Wrapper.Group#GROUP AIGroup - function( RangeZone, AIGroup, PlayerInRange ) - if PlayerInRange.Value == false then - self:Return( AIGroup ) - end - end - , RangeZone, AIGroup, PlayerInRange - ) - - end - self.Set:Remove( Client.UnitName ) - end - else - if not AIGroup or not AIGroup:IsAlive() == true then - self:E( "Client " .. Client.UnitName .. " not alive." ) - if not self.SpawnQueue[Client.UnitName] then - -- Spawn a new AI taking into account the spawn interval Earliest, Latest - self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) - self.SpawnQueue[Client.UnitName] = true - self:E( "New AI Spawned for Client " .. Client.UnitName ) - end - end - end - return true - end - ) - - self:__Monitor( 10 ) -end - - - ---- (AI) (FSM) Make AI patrol routes or zones. --- --- === --- --- 1) @{#AI_PATROLZONE} class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- ================================================================ --- The @{#AI_PATROLZONE} class implements the core functions to patrol a @{Zone} by an AIR @{Controllable} @{Group}. --- The patrol algorithm works that for each airplane patrolling, upon arrival at the patrol zone, --- a random point is selected as the route point within the 3D space, within the given boundary limits. --- The airplane will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. --- Upon arrival at the random 3D point, a new 3D random point will be selected within the patrol zone using the given limits. --- This cycle will continue until a fuel treshold has been reached by the airplane. --- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. --- --- 1.1) AI_PATROLZONE constructor: --- ---------------------------- --- --- * @{#AI_PATROLZONE.New}(): Creates a new AI_PATROLZONE object. --- --- 1.2) AI_PATROLZONE state machine: --- ---------------------------------- --- The AI_PATROLZONE is a state machine: it manages the different events and states of the AIControllable it is controlling. --- --- ### 1.2.1) AI_PATROLZONE Events: --- --- * @{#AI_PATROLZONE.Route}( AIControllable ): A new 3D route point is selected and the AIControllable will fly towards that point with the given speed. --- * @{#AI_PATROLZONE.Patrol}( AIControllable ): The AIControllable reports it is patrolling. This event is called every 30 seconds. --- * @{#AI_PATROLZONE.RTB}( AIControllable ): The AIControllable will report return to base. --- * @{#AI_PATROLZONE.End}( AIControllable ): The end of the AI_PATROLZONE process. --- * @{#AI_PATROLZONE.Dead}( AIControllable ): The AIControllable is dead. The AI_PATROLZONE process will be ended. --- --- ### 1.2.2) AI_PATROLZONE States: --- --- * **Route**: A new 3D route point is selected and the AIControllable will fly towards that point with the given speed. --- * **Patrol**: The AIControllable is patrolling. This state is set every 30 seconds, so every 30 seconds, a state transition method can be used. --- * **RTB**: The AIControllable reports it wants to return to the base. --- * **Dead**: The AIControllable is dead ... --- * **End**: The process has come to an end. --- --- ### 1.2.3) AI_PATROLZONE state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- An example how to manage a state transition for an AI_PATROLZONE object **Patrol** for the state **RTB**: --- --- local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone" ) --- local PatrolZone = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) --- --- local PatrolSpawn = SPAWN:New( "Patrol Group" ) --- local PatrolGroup = PatrolSpawn:Spawn() --- --- local Patrol = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 300, 600 ) --- Patrol:SetControllable( PatrolGroup ) --- Patrol:ManageFuel( 0.2, 60 ) --- --- **OnBefore**RTB( AIGroup ) will be called by the AI_PATROLZONE object when the AIGroup reports RTB, but **before** the RTB default action is processed by the AI_PATROLZONE object. --- --- --- State transition function for the AI_PATROLZONE **Patrol** object --- -- @param #AI_PATROLZONE self --- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup --- -- @return #boolean If false is returned, then the OnAfter state transition method will not be called. --- function Patrol:OnBeforeRTB( AIGroup ) --- AIGroup:MessageToRed( "Returning to base", 20 ) --- end --- --- **OnAfter**RTB( AIGroup ) will be called by the AI_PATROLZONE object when the AIGroup reports RTB, but **after** the RTB default action was processed by the AI_PATROLZONE object. --- --- --- State transition function for the AI_PATROLZONE **Patrol** object --- -- @param #AI_PATROLZONE self --- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup --- -- @return #Wrapper.Controllable#CONTROLLABLE The new AIGroup object that is set to be patrolling the zone. --- function Patrol:OnAfterRTB( AIGroup ) --- return PatrolSpawn:Spawn() --- end --- --- 1.3) Manage the AI_PATROLZONE parameters: --- ------------------------------------------ --- The following methods are available to modify the parameters of a AI_PATROLZONE object: --- --- * @{#AI_PATROLZONE.SetControllable}(): Set the AIControllable. --- * @{#AI_PATROLZONE.GetControllable}(): Get the AIControllable. --- * @{#AI_PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol. --- * @{#AI_PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol. --- --- 1.3) Manage the out of fuel in the AI_PATROLZONE: --- ---------------------------------------------- --- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base. --- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. --- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROLZONE. --- Once the time is finished, the old AIControllable will return to the base. --- Use the method @{#AI_PATROLZONE.ManageFuel}() to have this proces in place. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-09-01: Initial class and API. --- --- === --- --- AUTHORS and CONTRIBUTIONS --- ========================= --- --- ### Contributions: --- --- * **DutchBaron**: Testing. --- * **Pikey**: Testing and API concept review. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming. --- --- --- @module AI_Patrol - ---- AI_PATROLZONE class --- @type AI_PATROLZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. --- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @extends Core.Fsm#FSM_CONTROLLABLE -AI_PATROLZONE = { - ClassName = "AI_PATROLZONE", -} - - - ---- Creates a new AI_PATROLZONE object --- @param #AI_PATROLZONE self --- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @return #AI_PATROLZONE self --- @usage --- -- Define a new AI_PATROLZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. --- PatrolZone = ZONE:New( 'PatrolZone' ) --- PatrolSpawn = SPAWN:New( 'Patrol Group' ) --- PatrolArea = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 600, 900 ) -function AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_CONTROLLABLE - - - self.PatrolZone = PatrolZone - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed - - self.PatrolFuelTresholdPercentage = 0.2 - - - self:SetStartState( "None" ) - -do self:AddTransition( "*", "Start", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnBeforeStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnAfterStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Start. - -- @function [parent=#AI_PATROLZONE] Start - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Start - -- @function [parent=#AI_PATROLZONE] __Start - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "*", "Route", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnBeforeRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnAfterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Route. - -- @function [parent=#AI_PATROLZONE] Route - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Route - -- @function [parent=#AI_PATROLZONE] __Route - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "*", "Patrol", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnEnterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnBeforePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnAfterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Patrol. - -- @function [parent=#AI_PATROLZONE] Patrol - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Patrol - -- @function [parent=#AI_PATROLZONE] __Patrol - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "Patrol", "RTB", "RTB" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnEnterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnBeforeRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnAfterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for RTB. - -- @function [parent=#AI_PATROLZONE] RTB - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for RTB - -- @function [parent=#AI_PATROLZONE] __RTB - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - - return self -end - - - - ---- Sets (modifies) the minimum and maximum speed of the patrol. --- @param #AI_PATROLZONE self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) - self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) - - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed -end - - - ---- Sets the floor and ceiling altitude of the patrol. --- @param #AI_PATROLZONE self --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) - self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) - - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude -end - - - ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewPatrolRoute( AIControllable ) - - AIControllable:T( "NewPatrolRoute" ) - local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolCore.Zone#AI_PATROLZONE - PatrolZone:__Route( 1 ) -end - - - - ---- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base. --- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. --- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROLZONE. --- Once the time is finished, the old AIControllable will return to the base. --- @param #AI_PATROLZONE self --- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. --- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime ) - - self.PatrolManageFuel = true - self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage - self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime - - return self -end - ---- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. --- @param #AI_PATROLZONE self --- @return #AI_PATROLZONE self -function AI_PATROLZONE:onenterRoute() - - self:F2() - - local PatrolRoute = {} - - if self.Controllable:IsAlive() then - --- Determine if the AIControllable is within the PatrolZone. - -- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point. - --- --- Calculate the current route point. --- local CurrentVec2 = self.Controllable:GetVec2() --- local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() --- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) --- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( --- POINT_VEC3.RoutePointAltType.BARO, --- POINT_VEC3.RoutePointType.TurningPoint, --- POINT_VEC3.RoutePointAction.TurningPoint, --- ToPatrolZoneSpeed, --- true --- ) --- --- PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint - - self:T2( PatrolRoute ) - - if self.Controllable:IsNotInZone( self.PatrolZone ) then - --- Find a random 2D point in PatrolZone. - local ToPatrolZoneVec2 = self.PatrolZone:GetRandomVec2() - self:T2( ToPatrolZoneVec2 ) - - --- Define Speed and Altitude. - local ToPatrolZoneAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) - local ToPatrolZoneSpeed = self.PatrolMaxSpeed - self:T2( ToPatrolZoneSpeed ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToPatrolZonePointVec3 = POINT_VEC3:New( ToPatrolZoneVec2.x, ToPatrolZoneAltitude, ToPatrolZoneVec2.y ) - - --- Create a route point of type air. - local ToPatrolZoneRoutePoint = ToPatrolZonePointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToPatrolZoneSpeed, - true - ) - - PatrolRoute[#PatrolRoute+1] = ToPatrolZoneRoutePoint - - end - - --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. - - --- Find a random 2D point in PatrolZone. - local ToTargetVec2 = self.PatrolZone:GetRandomVec2() - self:T2( ToTargetVec2 ) - - --- Define Speed and Altitude. - local ToTargetAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) - local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) - self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) - - --- Create a route point of type air. - local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - --ToTargetPointVec3:SmokeRed() - - PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint - - --- 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( PatrolRoute ) - - --- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ... - self.Controllable:SetState( self.Controllable, "PatrolZone", self ) - self.Controllable:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" ) - - --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) - - self:__Patrol( 30 ) - end - -end - - ---- @param #AI_PATROLZONE self -function AI_PATROLZONE:onenterPatrol() - self:F2() - - if self.Controllable and self.Controllable:IsAlive() then - - local Fuel = self.Controllable:GetUnit(1):GetFuel() - if Fuel < self.PatrolFuelTresholdPercentage then - local OldAIControllable = self.Controllable - local AIControllableTemplate = self.Controllable:GetTemplate() - - local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) - local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) ) - OldAIControllable:SetTask( TimedOrbitTask, 10 ) - - self:RTB() - else - self:__Patrol( 30 ) -- Execute the Patrol event after 30 seconds. - end - end - -end ---- Management of logical cargo objects, that can be transported from and to transportation carriers. --- --- === --- --- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): --- --- * AI_CARGO_UNIT, represented by a @{Unit} in a @{Group}: Cargo can be represented by a Unit in a Group. Destruction of the Unit will mean that the cargo is lost. --- * CARGO_STATIC, represented by a @{Static}: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost. --- * AI_CARGO_PACKAGE, contained in a @{Unit} of a @{Group}: Cargo can be contained within a Unit of a Group. The cargo can be **delivered** by the @{Unit}. If the Unit is destroyed, the cargo will be destroyed also. --- * AI_CARGO_PACKAGE, Contained in a @{Static}: Cargo can be contained within a Static. The cargo can be **collected** from the @Static. If the @{Static} is destroyed, the cargo will be destroyed. --- * CARGO_SLINGLOAD, represented by a @{Cargo} that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost. --- --- * AI_CARGO_GROUPED, represented by a Group of CARGO_UNITs. --- --- 1) @{AI.AI_Cargo#AI_CARGO} class, extends @{Core.Fsm#FSM_PROCESS} --- ========================================================================== --- The @{#AI_CARGO} class defines the core functions that defines a cargo object within MOOSE. --- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. --- --- The AI_CARGO is a state machine: it manages the different events and states of the cargo. --- All derived classes from AI_CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. --- --- ## 1.2.1) AI_CARGO Events: --- --- * @{#AI_CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. --- * @{#AI_CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. --- * @{#AI_CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. --- * @{#AI_CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. --- * @{#AI_CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. --- --- ## 1.2.2) AI_CARGO States: --- --- * **UnLoaded**: The cargo is unloaded from a carrier. --- * **Boarding**: The cargo is currently boarding (= running) into a carrier. --- * **Loaded**: The cargo is loaded into a carrier. --- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. --- * **Dead**: The cargo is dead ... --- * **End**: The process has come to an end. --- --- ## 1.2.3) AI_CARGO state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Leaving** the state. --- The state transition method needs to start with the name **OnLeave + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **Entering** the state. --- The state transition method needs to start with the name **OnEnter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- 2) #AI_CARGO_UNIT class --- ==================== --- The AI_CARGO_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. --- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. --- --- 5) #AI_CARGO_GROUPED class --- ======================= --- The AI_CARGO_GROUPED class defines a cargo that is represented by a group of UNIT objects within the simulator, and can be transported by a carrier. --- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. --- --- This module is still under construction, but is described above works already, and will keep working ... --- --- @module Cargo - --- Events - --- Board - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] Board --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] __Board --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnBoard - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] UnBoard --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] __UnBoard --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - - --- Load - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] Load --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] __Load --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnLoad - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] UnLoad --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] __UnLoad --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - --- State Transition Functions - --- UnLoaded - ---- @function [parent=#AI_CARGO] OnLeaveUnLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterUnLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Loaded - ---- @function [parent=#AI_CARGO] OnLeaveLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Boarding - ---- @function [parent=#AI_CARGO] OnLeaveBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- UnBoarding - ---- @function [parent=#AI_CARGO] OnLeaveUnBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterUnBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - - --- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. - -CARGOS = {} - -do -- AI_CARGO - - --- @type AI_CARGO - -- @extends Core.Fsm#FSM_PROCESS - -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. - -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. - -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. - -- @field #number ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier. - -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. - -- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... - -- @field Wrapper.Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... - -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. - -- @field #boolean Moveable This flag defines if the cargo is moveable. - -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. - -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - AI_CARGO = { - ClassName = "AI_CARGO", - Type = nil, - Name = nil, - Weight = nil, - CargoObject = nil, - CargoCarrier = nil, - Representable = false, - Slingloadable = false, - Moveable = false, - Containable = false, - } - ---- @type AI_CARGO.CargoObjects --- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - - ---- AI_CARGO Constructor. This class is an abstract class and should not be instantiated. --- @param #AI_CARGO self --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO -function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) - - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:SetStartState( "UnLoaded" ) - self:AddTransition( "UnLoaded", "Board", "Boarding" ) - self:AddTransition( "Boarding", "Boarding", "Boarding" ) - self:AddTransition( "Boarding", "Load", "Loaded" ) - self:AddTransition( "UnLoaded", "Load", "Loaded" ) - self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) - self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) - - - self.Type = Type - self.Name = Name - self.Weight = Weight - self.ReportRadius = ReportRadius - self.NearRadius = NearRadius - self.CargoObject = nil - self.CargoCarrier = nil - self.Representable = false - self.Slingloadable = false - self.Moveable = false - self.Containable = false - - - self.CargoScheduler = SCHEDULER:New() - - CARGOS[self.Name] = self - - return self -end - - ---- Template method to spawn a new representation of the AI_CARGO in the simulator. --- @param #AI_CARGO self --- @return #AI_CARGO -function AI_CARGO:Spawn( PointVec2 ) - self:F() - -end - - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 PointVec2 --- @return #boolean -function AI_CARGO:IsNear( PointVec2 ) - self:F( { PointVec2 } ) - - local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - -end - -do -- AI_CARGO_REPRESENTABLE - - --- @type AI_CARGO_REPRESENTABLE - -- @extends #AI_CARGO - AI_CARGO_REPRESENTABLE = { - ClassName = "AI_CARGO_REPRESENTABLE" - } - ---- AI_CARGO_REPRESENTABLE Constructor. --- @param #AI_CARGO_REPRESENTABLE self --- @param Wrapper.Controllable#Controllable CargoObject --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_REPRESENTABLE -function AI_CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - return self -end - ---- Route a cargo unit to a PointVec2. --- @param #AI_CARGO_REPRESENTABLE self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #number Speed --- @return #AI_CARGO_REPRESENTABLE -function AI_CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:F2( ToPointVec2 ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) - Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - return self -end - -end -- AI_CARGO - -do -- AI_CARGO_UNIT - - --- @type AI_CARGO_UNIT - -- @extends #AI_CARGO_REPRESENTABLE - AI_CARGO_UNIT = { - ClassName = "AI_CARGO_UNIT" - } - ---- AI_CARGO_UNIT Constructor. --- @param #AI_CARGO_UNIT self --- @param Wrapper.Unit#UNIT CargoUnit --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_UNIT -function AI_CARGO_UNIT:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_UNIT - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:T( CargoUnit ) - self.CargoObject = CargoUnit - - self:T( self.ClassName ) - - return self -end - ---- Enter UnBoarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2 ) - self:F() - - local Angle = 180 - local Speed = 10 - local DeployDistance = 5 - local RouteDistance = 60 - - if From == "Loaded" then - - local CargoCarrierPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, CargoDeployHeading ) - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 - - local FromPointVec2 = CargoCarrierPointVec2 - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) - self.CargoCarrier = nil - - local Points = {} - Points[#Points+1] = FromPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - - self:__UnBoarding( 1, ToPointVec2 ) - end - end - -end - ---- Leave UnBoarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - if self:IsNear( ToPointVec2 ) then - return true - else - self:__UnBoarding( 1, ToPointVec2 ) - end - return false - end - -end - ---- UnBoard Event. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - end - - self:__UnLoad( 1, ToPointVec2 ) - -end - - - ---- Enter UnLoaded State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 -function AI_CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "Loaded" then - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or POINT_VEC2:New( CargoDeployPointVec2:GetX(), CargoDeployPointVec2:GetY() ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - -end - - - ---- Enter Boarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local Speed = 10 - local Angle = 180 - local Distance = 5 - - if From == "UnLoaded" then - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - end - -end - ---- Leave Boarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if self:IsNear( CargoCarrier:GetPointVec2() ) then - self:__Load( 1, CargoCarrier ) - return true - else - self:__Boarding( 1, CargoCarrier ) - end - return false -end - ---- Loaded State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:F() - - self.CargoCarrier = CargoCarrier - - -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self:T("Destroying") - self.CargoObject:Destroy() - end -end - - ---- Board Event. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier ) - self:F() - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only move the group to the carrier when the cargo is not in the air - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - self:Load( CargoCarrier ) - end - -end - -end - -do -- AI_CARGO_PACKAGE - - --- @type AI_CARGO_PACKAGE - -- @extends #AI_CARGO_REPRESENTABLE - AI_CARGO_PACKAGE = { - ClassName = "AI_CARGO_PACKAGE" - } - ---- AI_CARGO_PACKAGE Constructor. --- @param #AI_CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_PACKAGE -function AI_CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_PACKAGE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:T( CargoCarrier ) - self.CargoCarrier = CargoCarrier - - return self -end - ---- Board Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number BoardDistance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. - if not self.CargoInAir then - - local Points = {} - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - -end - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #AI_CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier --- @return #boolean -function AI_CARGO_PACKAGE:IsNear( CargoCarrier ) - self:F() - - local CargoCarrierPoint = CargoCarrier:GetPointVec2() - - local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - ---- Boarded Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) - else - self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - end -end - ---- UnBoard Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Speed --- @param #number UnLoadDistance --- @param #number UnBoardDistance --- @param #number Radius --- @param #number Angle -function AI_CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) - - local Points = {} - - local StartPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = CargoCarrier:TaskRoute( Points ) - CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:__UnBoarded( 1 , CargoCarrier, Speed ) - -end - ---- UnBoarded Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__UnLoad( 1, CargoCarrier, Speed ) - else - self:__UnBoarded( 1, CargoCarrier, Speed ) - end -end - ---- Load Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number LoadDistance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:F() - - self.CargoCarrier = CargoCarrier - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) - - local Points = {} - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - ---- UnLoad Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Distance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) - self:F() - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - self.CargoCarrier = CargoCarrier - - local Points = {} - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - - -end - -do -- AI_CARGO_GROUP - - --- @type AI_CARGO_GROUP - -- @extends AI.AI_Cargo#AI_CARGO - -- @field Set#SET_BASE CargoSet A set of cargo objects. - -- @field #string Name A string defining the name of the cargo group. The name is the unique identifier of the cargo. - AI_CARGO_GROUP = { - ClassName = "AI_CARGO_GROUP", - } - ---- AI_CARGO_GROUP constructor. --- @param #AI_CARGO_GROUP self --- @param Core.Set#Set_BASE CargoSet --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_GROUP -function AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, 0, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUP - self:F( { Type, Name, ReportRadius, NearRadius } ) - - self.CargoSet = CargoSet - - - return self -end - -end -- AI_CARGO_GROUP - -do -- AI_CARGO_GROUPED - - --- @type AI_CARGO_GROUPED - -- @extends AI.AI_Cargo#AI_CARGO_GROUP - AI_CARGO_GROUPED = { - ClassName = "AI_CARGO_GROUPED", - } - ---- AI_CARGO_GROUPED constructor. --- @param #AI_CARGO_GROUPED self --- @param Core.Set#Set_BASE CargoSet --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_GROUPED -function AI_CARGO_GROUPED:New( CargoSet, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUPED - self:F( { Type, Name, ReportRadius, NearRadius } ) - - return self -end - ---- Enter Boarding State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if From == "UnLoaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:__Board( 1, CargoCarrier ) - end - ) - - self:__Boarding( 1, CargoCarrier ) - end - -end - ---- Enter Loaded State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterLoaded( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if From == "UnLoaded" then - -- For each Cargo object within the AI_CARGO_GROUPED, load each cargo to the CargoCarrier. - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) - end - end -end - ---- Leave Boarding State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onleaveBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local Boarded = true - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "Loaded" ) then - Boarded = false - end - end - - if not Boarded then - self:__Boarding( 1, CargoCarrier ) - else - self:__Load( 1, CargoCarrier ) - end - return Boarded -end - ---- Enter UnBoarding State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterUnBoarding( From, Event, To, ToPointVec2 ) - self:F() - - local Timer = 1 - - if From == "Loaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:__UnBoard( Timer, ToPointVec2 ) - Timer = Timer + 10 - end - ) - - self:__UnBoarding( 1, ToPointVec2 ) - end - -end - ---- Leave UnBoarding State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) then - UnBoarded = false - end - end - - if UnBoarded then - return true - else - self:__UnBoarding( 1, ToPointVec2 ) - end - - return false - end - -end - ---- UnBoard Event. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onafterUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - self:__UnLoad( 1, ToPointVec2 ) -end - - - ---- Enter UnLoaded State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - if From == "Loaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:UnLoad( ToPointVec2 ) - end - ) - - end - -end - -end -- AI_CARGO_GROUPED - - - ---- SP:Y MP:Y AI:Y HU:N TYP:Air -- This module contains the AI_CAS_ZONE class. --- --- === --- --- 1) @{#AI_CAS_ZONE} class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- ================================================================ --- The @{#AI_CAS_ZONE} class implements the core functions to CAS a @{Zone} by an AIR @{Controllable} @{Group}. --- --- 1.1) AI_CAS_ZONE constructor: --- ---------------------------- --- --- * @{#AI_CAS_ZONE.New}(): Creates a new AI_CAS_ZONE object. --- --- 1.2) AI_CAS_ZONE state machine: --- ---------------------------------- --- The AI_CAS_ZONE is a state machine: it manages the different events and states of the AIControllable it is controlling. --- --- ### 1.2.1) AI_CAS_ZONE Events: --- --- * @{#AI_CAS_ZONE.TakeOff}( AIControllable ): The AI is taking-off from an airfield. --- * @{#AI_CAS_ZONE.Hold}( AIControllable ): The AI is holding in airspace at a zone. --- * @{#AI_CAS_ZONE.Engage}( AIControllable ): The AI is engaging the targets. --- * @{#AI_CAS_ZONE.WeaponReleased}( AIControllable ): The AI has released a weapon to the target. --- * @{#AI_CAS_ZONE.Destroy}( AIControllable ): The AI has destroyed a target. --- * @{#AI_CAS_ZONE.Complete}( AIControllable ): The AI has destroyed all defined targets. --- * @{#AI_CAS_ZONE.RTB}( AIControllable ): The AI is returning to the home base. --- --- ### 1.2.2) AI_CAS_ZONE States: --- --- --- ### 1.2.3) AI_CAS_ZONE state transition methods: --- --- --- 1.3) Manage the AI_CAS_ZONE parameters: --- ------------------------------------------ --- The following methods are available to modify the parameters of an AI_CAS_ZONE object: --- --- * @{#AI_CAS_ZONE.SetControllable}(): Set the AIControllable. --- * @{#AI_CAS_ZONE.GetControllable}(): Get the AIControllable. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2017-01-12: Initial class and API. --- --- === --- --- AUTHORS and CONTRIBUTIONS --- ========================= --- --- ### Contributions: --- --- * **Quax**: Concept & Testing. --- * **Pikey**: Concept & Testing. --- --- ### Authors: --- --- * **FlightControl**: Concept, Design & Programming. --- --- --- @module Cas - - ---- AI_CAS_ZONE class --- @type AI_CAS_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. --- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. --- @extends AI.AI_Patrol#AI_PATROLZONE -AI_CAS_ZONE = { - ClassName = "AI_CAS_ZONE", -} - - - ---- Creates a new AI_CAS_ZONE object --- @param #AI_CAS_ZONE self --- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @param Core.Zone#ZONE EngageZone --- @return #AI_CAS_ZONE self -function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) ) -- #AI_CAS_ZONE - - self.PatrolZone = PatrolZone - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed - - self.EngageZone = EngageZone - - do self:AddTransition( { "Patrol", "Route", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Holding. - -- @function [parent=#AI_CAS_ZONE] OnLeaveHolding - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnBeforeEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnAfterEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Engage. - -- @function [parent=#AI_CAS_ZONE] Engage - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Engage - -- @function [parent=#AI_CAS_ZONE] __Engage - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - - do self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnBeforeFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnAfterFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean - - --- Embedded Event Trigger for Fired. - -- @function [parent=#AI_CAS_ZONE] Fired - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Fired - -- @function [parent=#AI_CAS_ZONE] __Fired - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - do self:AddTransition( "Engaging", "Destroy", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnBeforeDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnAfterDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Destroy. - -- @function [parent=#AI_CAS_ZONE] Destroy - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Destroy - -- @function [parent=#AI_CAS_ZONE] __Destroy - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - -do self:AddTransition( "Engaging", "Abort", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Abort. - -- @function [parent=#AI_CAS_ZONE] OnBeforeAbort - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Abort. - -- @function [parent=#AI_CAS_ZONE] OnAfterAbort - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Abort. - -- @function [parent=#AI_CAS_ZONE] Abort - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Abort - -- @function [parent=#AI_CAS_ZONE] __Abort - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_CAS_ZONE - - - do self:AddTransition( "Engaging", "Completed", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnBeforeCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnAfterCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Completed. - -- @function [parent=#AI_CAS_ZONE] Completed - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Completed - -- @function [parent=#AI_CAS_ZONE] __Completed - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - return self -end - - ---- onafter State Transition for Event Start. --- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To ) - - - if Controllable:IsAlive() then - self:__Route( 1 ) - end - - self:EventOnDead( self.OnDead ) - - Controllable:OptionROEHoldFire() - Controllable:OptionROTVertical() - -end - ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewEngageRoute( AIControllable ) - - AIControllable:T( "NewEngageRoute" ) - local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Patrol#AI_PATROLZONE - EngageZone:__Engage( 1 ) -end - - ---- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) - - if Controllable:IsAlive() then - - local EngageRoute = {} - - if self.Controllable:IsNotInZone( self.EngageZone ) then - - -- Find a random 2D point in EngageZone. - local ToEngageZoneVec2 = self.EngageZone:GetRandomVec2() - self:T2( ToEngageZoneVec2 ) - - -- Define Speed and Altitude. - local ToEngageZoneAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) - local ToEngageZoneSpeed = self.PatrolMaxSpeed - self:T2( ToEngageZoneSpeed ) - - -- Obtain a 3D @{Point} from the 2D point + altitude. - local ToEngageZonePointVec3 = POINT_VEC3:New( ToEngageZoneVec2.x, ToEngageZoneAltitude, ToEngageZoneVec2.y ) - - -- Create a route point of type air. - local ToEngageZoneRoutePoint = ToEngageZonePointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToEngageZoneSpeed, - true - ) - - EngageRoute[#EngageRoute+1] = ToEngageZoneRoutePoint - - end - - --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. - - --- Find a random 2D point in EngageZone. - local ToTargetVec2 = self.EngageZone:GetRandomVec2() - self:T2( ToTargetVec2 ) - - --- Define Speed and Altitude. - local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) - local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) - self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) - - --- Create a route point of type air. - local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - ToTargetPointVec3:SmokeRed() - - EngageRoute[#EngageRoute+1] = ToTargetRoutePoint - - - Controllable:OptionROEOpenFire() - Controllable:OptionROTPassiveDefense() - - local AttackTasks = {} - - local DetectedTargets = Controllable:GetDetectedTargets() - for TargetID, Target in pairs( DetectedTargets ) do - local TargetObject = Target.object - self:T( TargetObject ) - if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then - - local TargetUnit = UNIT:Find( TargetObject ) - local TargetUnitName = TargetUnit:GetName() - - if TargetUnit:IsInZone( self.EngageZone ) then - self:E( {"Engaging ", TargetUnit } ) - --local EngageTask = Controllable:EnRouteTaskEngageUnit( TargetUnit, 1 ) - AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( TargetUnit ) - end - - end - end - - EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) - - --- 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 ) - - --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... - self.Controllable:SetState( self.Controllable, "EngageZone", self ) - - self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) - - --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) - end -end - ---- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To ) - - Controllable:MessageToAll( "Destroyed a target", 15 , "Destroyed!" ) -end - ---- @param #AI_CAS_ZONE self --- @param Core.Event#EVENTDATA EventData -function AI_CAS_ZONE:OnDead( EventData ) - self:T( { "EventDead", EventData } ) - - if EventData.IniDCSUnit then - self:__Destroy( 1, EventData ) - end -end - - ---- (SP) (MP) (FSM) Accept or reject process for player (task) assignments. --- --- === --- --- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ASSIGN state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ASSIGN **Events**: --- --- These are the events defined in this class: --- --- * **Start**: Start the tasking acceptance process. --- * **Assign**: Assign the task. --- * **Reject**: Reject the task.. --- --- ### ACT_ASSIGN **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ASSIGN **States**: --- --- * **UnAssigned**: The player has not accepted the task. --- * **Assigned (*)**: The player has accepted the task. --- * **Rejected (*)**: The player has not accepted the task. --- * **Waiting**: The process is awaiting player feedback. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ASSIGN state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} --- --- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task. --- --- ## 1.1) ACT_ASSIGN_ACCEPT constructor: --- --- * @{#ACT_ASSIGN_ACCEPT.New}(): Creates a new ACT_ASSIGN_ACCEPT object. --- --- === --- --- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} --- --- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option. --- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task. --- The assignment type also allows to reject the task. --- --- ## 2.1) ACT_ASSIGN_MENU_ACCEPT constructor: --- ----------------------------------------- --- --- * @{#ACT_ASSIGN_MENU_ACCEPT.New}(): Creates a new ACT_ASSIGN_MENU_ACCEPT object. --- --- === --- --- @module Assign - - -do -- ACT_ASSIGN - - --- ACT_ASSIGN class - -- @type ACT_ASSIGN - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends Core.Fsm#FSM_PROCESS - ACT_ASSIGN = { - ClassName = "ACT_ASSIGN", - } - - - --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. - -- @param #ACT_ASSIGN self - -- @return #ACT_ASSIGN The task acceptance process. - function ACT_ASSIGN:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIGN" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "UnAssigned", "Start", "Waiting" ) - self:AddTransition( "Waiting", "Assign", "Assigned" ) - self:AddTransition( "Waiting", "Reject", "Rejected" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:AddEndState( "Assigned" ) - self:AddEndState( "Rejected" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "UnAssigned" ) - - return self - end - -end -- ACT_ASSIGN - - - -do -- ACT_ASSIGN_ACCEPT - - --- ACT_ASSIGN_ACCEPT class - -- @type ACT_ASSIGN_ACCEPT - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIGN - ACT_ASSIGN_ACCEPT = { - ClassName = "ACT_ASSIGN_ACCEPT", - } - - - --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. - -- @param #ACT_ASSIGN_ACCEPT self - -- @param #string TaskBriefing - function ACT_ASSIGN_ACCEPT:New( TaskBriefing ) - - local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_ACCEPT - - self.TaskBriefing = TaskBriefing - - return self - end - - function ACT_ASSIGN_ACCEPT:Init( FsmAssign ) - - self.TaskBriefing = FsmAssign.TaskBriefing - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_ACCEPT self - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:__Assign( 1 ) - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_ACCEPT self - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To ) - env.info( "in here" ) - self:E( { ProcessUnit, From, Event, To } ) - - local ProcessGroup = ProcessUnit:GetGroup() - - self:Message( "You are assigned to the task " .. self.Task:GetName() ) - - self.Task:Assign() - end - -end -- ACT_ASSIGN_ACCEPT - - -do -- ACT_ASSIGN_MENU_ACCEPT - - --- ACT_ASSIGN_MENU_ACCEPT class - -- @type ACT_ASSIGN_MENU_ACCEPT - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIGN - ACT_ASSIGN_MENU_ACCEPT = { - ClassName = "ACT_ASSIGN_MENU_ACCEPT", - } - - --- Init. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName - -- @param #string TaskBriefing - -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing ) - - -- Inherits from BASE - local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT - - self.TaskName = TaskName - self.TaskBriefing = TaskBriefing - - return self - end - - function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign ) - - self.TaskName = FsmAssign.TaskName - self.TaskBriefing = FsmAssign.TaskBriefing - end - - - --- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName - -- @param #string TaskBriefing - -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing ) - - self.TaskBriefing = TaskBriefing - self.TaskName = TaskName - - return self - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." ) - - local ProcessGroup = ProcessUnit:GetGroup() - - self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" ) - self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self ) - self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self ) - end - - --- Menu function. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuAssign() - self:E( ) - - self:__Assign( 1 ) - end - - --- Menu function. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuReject() - self:E( ) - - self:__Reject( 1 ) - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit.UnitNameFrom, Event, To } ) - - self.Menu:Remove() - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit.UnitName, From, Event, To } ) - - self.Menu:Remove() - --TODO: need to resolve this problem ... it has to do with the events ... - --self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event - ProcessUnit:Destroy() - end - -end -- ACT_ASSIGN_MENU_ACCEPT ---- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. --- --- === --- --- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ROUTE state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ROUTE **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. The process will go into the Report state. --- * **Report**: The process is reporting to the player the route to be followed. --- * **Route**: The process is routing the controllable. --- * **Pause**: The process is pausing the route of the controllable. --- * **Arrive**: The controllable has arrived at a route point. --- * **More**: There are more route points that need to be followed. The process will go back into the Report state. --- * **NoMore**: There are no more route points that need to be followed. The process will go into the Success state. --- --- ### ACT_ROUTE **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ROUTE **States**: --- --- * **None**: The controllable did not receive route commands. --- * **Arrived (*)**: The controllable has arrived at a route point. --- * **Aborted (*)**: The controllable has aborted the route path. --- * **Routing**: The controllable is understay to the route point. --- * **Pausing**: The process is pausing the routing. AI air will go into hover, AI ground will stop moving. Players can fly around. --- * **Success (*)**: All route points were reached. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ROUTE state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE} --- --- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}. --- The player receives on perioding times messages with the coordinates of the route to follow. --- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended. --- --- # 1.1) ACT_ROUTE_ZONE constructor: --- --- * @{#ACT_ROUTE_ZONE.New}(): Creates a new ACT_ROUTE_ZONE object. --- --- === --- --- @module Route - - -do -- ACT_ROUTE - - --- ACT_ROUTE class - -- @type ACT_ROUTE - -- @field Tasking.Task#TASK TASK - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends Core.Fsm#FSM_PROCESS - ACT_ROUTE = { - ClassName = "ACT_ROUTE", - } - - - --- Creates a new routing state machine. The process will route a CLIENT to a ZONE until the CLIENT is within that ZONE. - -- @param #ACT_ROUTE self - -- @return #ACT_ROUTE self - function ACT_ROUTE:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ROUTE" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "None", "Start", "Routing" ) - self:AddTransition( "*", "Report", "Reporting" ) - self:AddTransition( "*", "Route", "Routing" ) - self:AddTransition( "Routing", "Pause", "Pausing" ) - self:AddTransition( "*", "Abort", "Aborted" ) - self:AddTransition( "Routing", "Arrive", "Arrived" ) - self:AddTransition( "Arrived", "Success", "Success" ) - self:AddTransition( "*", "Fail", "Failed" ) - self:AddTransition( "", "", "" ) - self:AddTransition( "", "", "" ) - - self:AddEndState( "Arrived" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "None" ) - - return self - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE:onafterStart( ProcessUnit, From, Event, To ) - - - self:__Route( 1 ) - end - - --- Check if the controllable has arrived. - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @return #boolean - function ACT_ROUTE:onfuncHasArrived( ProcessUnit ) - return false - end - - --- StateMachine callback function - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To ) - self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } ) - - if ProcessUnit:IsAlive() then - self:F( "BeforeRoute 2" ) - local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic - if self.DisplayCount >= self.DisplayInterval then - self:T( { HasArrived = HasArrived } ) - if not HasArrived then - self:Report() - end - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - self:T( { DisplayCount = self.DisplayCount } ) - - if HasArrived then - self:__Arrive( 1 ) - else - self:__Route( 1 ) - end - - return HasArrived -- if false, then the event will not be executed... - end - - return false - - end - -end -- ACT_ROUTE - - - -do -- ACT_ROUTE_ZONE - - --- ACT_ROUTE_ZONE class - -- @type ACT_ROUTE_ZONE - -- @field Tasking.Task#TASK TASK - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ROUTE - ACT_ROUTE_ZONE = { - ClassName = "ACT_ROUTE_ZONE", - } - - - --- Creates a new routing state machine. The task will route a controllable to a ZONE until the controllable is within that ZONE. - -- @param #ACT_ROUTE_ZONE self - -- @param Core.Zone#ZONE_BASE TargetZone - function ACT_ROUTE_ZONE:New( TargetZone ) - local self = BASE:Inherit( self, ACT_ROUTE:New() ) -- #ACT_ROUTE_ZONE - - self.TargetZone = TargetZone - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - - return self - end - - function ACT_ROUTE_ZONE:Init( FsmRoute ) - - self.TargetZone = FsmRoute.TargetZone - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - end - - --- Method override to check if the controllable has arrived. - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @return #boolean - function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit ) - - if ProcessUnit:IsInZone( self.TargetZone ) then - local RouteText = "You have arrived within the zone." - self:Message( RouteText ) - end - - return ProcessUnit:IsInZone( self.TargetZone ) - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ROUTE_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE_ZONE:onenterReporting( ProcessUnit, From, Event, To ) - - local ZoneVec2 = self.TargetZone:GetVec2() - local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y ) - local TaskUnitVec2 = ProcessUnit:GetVec2() - local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y ) - local RouteText = "Route to " .. TaskUnitPointVec2:GetBRText( ZonePointVec2 ) .. " km to target." - self:Message( RouteText ) - end - -end -- ACT_ROUTE_ZONE ---- (SP) (MP) (FSM) Account for (Detect, count and report) DCS events occuring on DCS objects (units). --- --- === --- --- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ACCOUNT state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ACCOUNT **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. The process will go into the Report state. --- * **Event**: A relevant event has occured that needs to be accounted for. The process will go into the Account state. --- * **Report**: The process is reporting to the player the accounting status of the DCS events. --- * **More**: There are more DCS events that need to be accounted for. The process will go back into the Report state. --- * **NoMore**: There are no more DCS events that need to be accounted for. The process will go into the Success state. --- --- ### ACT_ACCOUNT **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ACCOUNT **States**: --- --- * **Assigned**: The player is assigned to the task. This is the initialization state for the process. --- * **Waiting**: the process is waiting for a DCS event to occur within the simulator. This state is set automatically. --- * **Report**: The process is Reporting to the players in the group of the unit. This state is set automatically every 30 seconds. --- * **Account**: The relevant DCS event has occurred, and is accounted for. --- * **Success (*)**: All DCS events were accounted for. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ACCOUNT state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- # 1) @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT} --- --- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units. --- The process is given a @{Set} of units that will be tracked upon successful destruction. --- The process will end after each target has been successfully destroyed. --- Each successful dead will trigger an Account state transition that can be scored, modified or administered. --- --- --- ## ACT_ACCOUNT_DEADS constructor: --- --- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object. --- --- === --- --- @module Account - - -do -- ACT_ACCOUNT - - --- ACT_ACCOUNT class - -- @type ACT_ACCOUNT - -- @field Set#SET_UNIT TargetSetUnit - -- @extends Core.Fsm#FSM_PROCESS - ACT_ACCOUNT = { - ClassName = "ACT_ACCOUNT", - TargetSetUnit = nil, - } - - --- Creates a new DESTROY process. - -- @param #ACT_ACCOUNT self - -- @return #ACT_ACCOUNT - function ACT_ACCOUNT:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New() ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "Assigned", "Start", "Waiting") - self:AddTransition( "*", "Wait", "Waiting") - self:AddTransition( "*", "Report", "Report") - self:AddTransition( "*", "Event", "Account") - self:AddTransition( "Account", "More", "Wait") - self:AddTransition( "Account", "NoMore", "Accounted") - self:AddTransition( "*", "Fail", "Failed") - - self:AddEndState( "Accounted" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "Assigned" ) - - return self - end - - --- Process Events - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onafterStart( ProcessUnit, From, Event, To ) - - self:EventOnDead( self.onfuncEventDead ) - - self:__Wait( 1 ) - end - - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onenterWaiting( ProcessUnit, From, Event, To ) - - if self.DisplayCount >= self.DisplayInterval then - self:Report() - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - return true -- Process always the event. - end - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event ) - - self:__NoMore( 1 ) - end - -end -- ACT_ACCOUNT - -do -- ACT_ACCOUNT_DEADS - - --- ACT_ACCOUNT_DEADS class - -- @type ACT_ACCOUNT_DEADS - -- @field Set#SET_UNIT TargetSetUnit - -- @extends #ACT_ACCOUNT - ACT_ACCOUNT_DEADS = { - ClassName = "ACT_ACCOUNT_DEADS", - TargetSetUnit = nil, - } - - - --- Creates a new DESTROY process. - -- @param #ACT_ACCOUNT_DEADS self - -- @param Set#SET_UNIT TargetSetUnit - -- @param #string TaskName - function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName ) - -- Inherits from BASE - local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS - - self.TargetSetUnit = TargetSetUnit - self.TaskName = TaskName - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - self.DisplayCategory = "HQ" -- Targets is the default display category - - return self - end - - function ACT_ACCOUNT_DEADS:Init( FsmAccount ) - - self.TargetSetUnit = FsmAccount.TargetSetUnit - self.TaskName = FsmAccount.TaskName - end - - - - function ACT_ACCOUNT_DEADS:_Destructor() - self:E("_Destructor") - - self:EventRemoveAll() - - end - - --- Process Events - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." ) - end - - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onenterAccount( ProcessUnit, From, Event, To, EventData ) - self:T( { ProcessUnit, EventData, From, Event, To } ) - - self:T({self.Controllable}) - - self.TargetSetUnit:Flush() - - if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then - local TaskGroup = ProcessUnit:GetGroup() - self.TargetSetUnit:RemoveUnitsByName( EventData.IniUnitName ) - self:Message( "You hit a target. Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." ) - end - end - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, From, Event, To, EventData ) - - if self.TargetSetUnit:Count() > 0 then - self:__More( 1 ) - else - self:__NoMore( 1 ) - end - end - - --- DCS Events - - --- @param #ACT_ACCOUNT_DEADS self - -- @param Event#EVENTDATA EventData - function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData ) - self:T( { "EventDead", EventData } ) - - if EventData.IniDCSUnit then - self:__Event( 1, EventData ) - end - end - -end -- ACT_ACCOUNT DEADS ---- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. --- --- === --- --- # @{#ACT_ASSIST} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ASSIST state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ASSIST **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. --- * **Next**: The process is smoking the targets in the given zone. --- --- ### ACT_ASSIST **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ASSIST **States**: --- --- * **None**: The controllable did not receive route commands. --- * **AwaitSmoke (*)**: The process is awaiting to smoke the targets in the zone. --- * **Smoking (*)**: The process is smoking the targets in the zone. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ASSIST state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST} --- --- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}. --- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour. --- At random intervals, a new target is smoked. --- --- # 1.1) ACT_ASSIST_SMOKE_TARGETS_ZONE constructor: --- --- * @{#ACT_ASSIST_SMOKE_TARGETS_ZONE.New}(): Creates a new ACT_ASSIST_SMOKE_TARGETS_ZONE object. --- --- === --- --- @module Smoke - -do -- ACT_ASSIST - - --- ACT_ASSIST class - -- @type ACT_ASSIST - -- @extends Core.Fsm#FSM_PROCESS - ACT_ASSIST = { - ClassName = "ACT_ASSIST", - } - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST self - -- @return #ACT_ASSIST - function ACT_ASSIST:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIST" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "None", "Start", "AwaitSmoke" ) - self:AddTransition( "AwaitSmoke", "Next", "Smoking" ) - self:AddTransition( "Smoking", "Next", "AwaitSmoke" ) - self:AddTransition( "*", "Stop", "Success" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:AddEndState( "Failed" ) - self:AddEndState( "Success" ) - - self:SetStartState( "None" ) - - return self - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ASSIST self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIST:onafterStart( ProcessUnit, From, Event, To ) - - local ProcessGroup = ProcessUnit:GetGroup() - local MissionMenu = self:GetMission():GetMissionMenu( ProcessGroup ) - - local function MenuSmoke( MenuParam ) - self:E( MenuParam ) - local self = MenuParam.self - local SmokeColor = MenuParam.SmokeColor - self.SmokeColor = SmokeColor - self:__Next( 1 ) - end - - self.Menu = MENU_GROUP:New( ProcessGroup, "Target acquisition", MissionMenu ) - self.MenuSmokeBlue = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop blue smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Blue } ) - self.MenuSmokeGreen = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop green smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Green } ) - self.MenuSmokeOrange = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Orange smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Orange } ) - self.MenuSmokeRed = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Red smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Red } ) - self.MenuSmokeWhite = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop White smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.White } ) - end - -end - -do -- ACT_ASSIST_SMOKE_TARGETS_ZONE - - --- ACT_ASSIST_SMOKE_TARGETS_ZONE class - -- @type ACT_ASSIST_SMOKE_TARGETS_ZONE - -- @field Set#SET_UNIT TargetSetUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIST - ACT_ASSIST_SMOKE_TARGETS_ZONE = { - ClassName = "ACT_ASSIST_SMOKE_TARGETS_ZONE", - } - --- function ACT_ASSIST_SMOKE_TARGETS_ZONE:_Destructor() --- self:E("_Destructor") --- --- self.Menu:Remove() --- self:EventRemoveAll() --- end - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit - -- @param Core.Zone#ZONE_BASE TargetZone - function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone ) - local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - return self - end - - function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( FsmSmoke ) - - self.TargetSetUnit = FsmSmoke.TargetSetUnit - self.TargetZone = FsmSmoke.TargetZone - end - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self - function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone ) - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - return self - end - - --- StateMachine callback function - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIST_SMOKE_TARGETS_ZONE:onenterSmoking( ProcessUnit, From, Event, To ) - - self.TargetSetUnit:ForEachUnit( - --- @param Wrapper.Unit#UNIT SmokeUnit - function( SmokeUnit ) - if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then - SCHEDULER:New( self, - function() - if SmokeUnit:IsAlive() then - SmokeUnit:Smoke( self.SmokeColor, 150 ) - end - end, {}, math.random( 10, 60 ) - ) - end - end - ) - - end - -end--- A COMMANDCENTER is the owner of multiple missions within MOOSE. --- A COMMANDCENTER governs multiple missions, the tasking and the reporting. --- @module CommandCenter - - - ---- The REPORT class --- @type REPORT --- @extends Core.Base#BASE -REPORT = { - ClassName = "REPORT", -} - ---- Create a new REPORT. --- @param #REPORT self --- @param #string Title --- @return #REPORT -function REPORT:New( Title ) - - local self = BASE:Inherit( self, BASE:New() ) - - self.Report = {} - self.Report[#self.Report+1] = Title - - return self -end - ---- Add a new line to a REPORT. --- @param #REPORT self --- @param #string Text --- @return #REPORT -function REPORT:Add( Text ) - self.Report[#self.Report+1] = Text - return self.Report[#self.Report+1] -end - -function REPORT:Text() - return table.concat( self.Report, "\n" ) -end - ---- The COMMANDCENTER class --- @type COMMANDCENTER --- @field Wrapper.Group#GROUP HQ --- @field Dcs.DCSCoalitionWrapper.Object#coalition CommandCenterCoalition --- @list Missions --- @extends Core.Base#BASE -COMMANDCENTER = { - ClassName = "COMMANDCENTER", - CommandCenterName = "", - CommandCenterCoalition = nil, - CommandCenterPositionable = nil, - Name = "", -} ---- The constructor takes an IDENTIFIABLE as the HQ command center. --- @param #COMMANDCENTER self --- @param Wrapper.Positionable#POSITIONABLE CommandCenterPositionable --- @param #string CommandCenterName --- @return #COMMANDCENTER -function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) - - local self = BASE:Inherit( self, BASE:New() ) - - self.CommandCenterPositionable = CommandCenterPositionable - self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName() - self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition() - - self.Missions = {} - - self:EventOnBirth( - --- @param #COMMANDCENTER self - --- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - self:E( { EventData } ) - local EventGroup = GROUP:Find( EventData.IniDCSGroup ) - if EventGroup and self:HasGroup( EventGroup ) then - local MenuReporting = MENU_GROUP:New( EventGroup, "Reporting", self.CommandCenterMenu ) - local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Summary Report", MenuReporting, self.ReportSummary, self, EventGroup ) - local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Details Report", MenuReporting, self.ReportDetails, self, EventGroup ) - self:ReportSummary( EventGroup ) - end - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:JoinUnit( PlayerUnit ) - Mission:ReportDetails() - end - - end - ) - - -- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do. - -- For these elements, it will= - -- - Set the correct menu. - -- - Assign the PlayerUnit to the Task if required. - -- - Send a message to the other players in the group that this player has joined. - self:EventOnPlayerEnterUnit( - --- @param #COMMANDCENTER self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:JoinUnit( PlayerUnit ) - Mission:ReportDetails() - end - end - ) - - -- Handle when a player leaves a slot and goes back to spectators ... - -- The PlayerUnit will be UnAssigned from the Task. - -- When there is no Unit left running the Task, the Task goes into Abort... - self:EventOnPlayerLeaveUnit( - --- @param #TASK self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - Mission:AbortUnit( PlayerUnit ) - end - end - ) - - -- Handle when a player leaves a slot and goes back to spectators ... - -- The PlayerUnit will be UnAssigned from the Task. - -- When there is no Unit left running the Task, the Task goes into Abort... - self:EventOnCrash( - --- @param #TASK self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - Mission:CrashUnit( PlayerUnit ) - end - end - ) - - return self -end - ---- Gets the name of the HQ command center. --- @param #COMMANDCENTER self --- @return #string -function COMMANDCENTER:GetName() - - return self.CommandCenterName -end - ---- Gets the POSITIONABLE of the HQ command center. --- @param #COMMANDCENTER self --- @return Wrapper.Positionable#POSITIONABLE -function COMMANDCENTER:GetPositionable() - return self.CommandCenterPositionable -end - ---- Get the Missions governed by the HQ command center. --- @param #COMMANDCENTER self --- @return #list -function COMMANDCENTER:GetMissions() - - return self.Missions -end - ---- Add a MISSION to be governed by the HQ command center. --- @param #COMMANDCENTER self --- @param Tasking.Mission#MISSION Mission --- @return Tasking.Mission#MISSION -function COMMANDCENTER:AddMission( Mission ) - - self.Missions[Mission] = Mission - - return Mission -end - ---- Removes a MISSION to be governed by the HQ command center. --- The given Mission is not nilified. --- @param #COMMANDCENTER self --- @param Tasking.Mission#MISSION Mission --- @return Tasking.Mission#MISSION -function COMMANDCENTER:RemoveMission( Mission ) - - self.Missions[Mission] = nil - - return Mission -end - ---- Sets the menu structure of the Missions governed by the HQ command center. --- @param #COMMANDCENTER self -function COMMANDCENTER:SetMenu() - self:F() - - self.CommandCenterMenu = self.CommandCenterMenu or MENU_COALITION:New( self.CommandCenterCoalition, "Command Center (" .. self:GetName() .. ")" ) - - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:RemoveMenu() - end - - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:SetMenu() - end -end - - ---- Checks of the COMMANDCENTER has a GROUP. --- @param #COMMANDCENTER self --- @param Wrapper.Group#GROUP --- @return #boolean -function COMMANDCENTER:HasGroup( MissionGroup ) - - local Has = false - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - if Mission:HasGroup( MissionGroup ) then - Has = true - break - end - end - - return Has -end - ---- Send a CC message to a GROUP. --- @param #COMMANDCENTER self --- @param #string Message --- @param Wrapper.Group#GROUP TaskGroup --- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. -function COMMANDCENTER:MessageToGroup( Message, TaskGroup, Name ) - - local Prefix = Name and "@ Group (" .. Name .. "): " or '' - Message = Prefix .. Message - self:GetPositionable():MessageToGroup( Message , 20, TaskGroup, self:GetName() ) - -end - ---- Send a CC message to the coalition of the CC. --- @param #COMMANDCENTER self -function COMMANDCENTER:MessageToCoalition( Message ) - - local CCCoalition = self:GetPositionable():GetCoalition() - self:GetPositionable():MessageToBlue( Message , 20, CCCoalition ) - -end - ---- Report the status of all MISSIONs to a GROUP. --- Each Mission is listed, with an indication how many Tasks are still to be completed. --- @param #COMMANDCENTER self -function COMMANDCENTER:ReportSummary( ReportGroup ) - self:E( ReportGroup ) - - local Report = REPORT:New() - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - Report:Add( " - " .. Mission:ReportOverview() ) - end - - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) - -end - ---- Report the status of a Task to a Group. --- Report the details of a Mission, listing the Mission, and all the Task details. --- @param #COMMANDCENTER self -function COMMANDCENTER:ReportDetails( ReportGroup, Task ) - self:E( ReportGroup ) - - local Report = REPORT:New() - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - Report:Add( " - " .. Mission:ReportDetails() ) - end - - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) -end - ---- A MISSION is the main owner of a Mission orchestration within MOOSE . The Mission framework orchestrates @{CLIENT}s, @{TASK}s, @{STAGE}s etc. --- A @{CLIENT} needs to be registered within the @{MISSION} through the function @{AddClient}. A @{TASK} needs to be registered within the @{MISSION} through the function @{AddTask}. --- @module Mission - ---- The MISSION class --- @type MISSION --- @field #MISSION.Clients _Clients --- @field Core.Menu#MENU_COALITION MissionMenu --- @field #string MissionBriefing --- @extends Core.Fsm#FSM -MISSION = { - ClassName = "MISSION", - Name = "", - MissionStatus = "PENDING", - _Clients = {}, - TaskMenus = {}, - TaskCategoryMenus = {}, - TaskTypeMenus = {}, - _ActiveTasks = {}, - GoalFunction = nil, - MissionReportTrigger = 0, - MissionProgressTrigger = 0, - MissionReportShow = false, - MissionReportFlash = false, - MissionTimeInterval = 0, - MissionCoalition = "", - SUCCESS = 1, - FAILED = 2, - REPEAT = 3, - _GoalTasks = {} -} - ---- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. --- @param #MISSION self --- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter --- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. --- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. --- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. --- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... --- @return #MISSION self -function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) - - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM - - self:SetStartState( "Idle" ) - - self:AddTransition( "Idle", "Start", "Ongoing" ) - self:AddTransition( "Ongoing", "Stop", "Idle" ) - self:AddTransition( "Ongoing", "Complete", "Completed" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } ) - - self.CommandCenter = CommandCenter - CommandCenter:AddMission( self ) - - self.Name = MissionName - self.MissionPriority = MissionPriority - self.MissionBriefing = MissionBriefing - self.MissionCoalition = MissionCoalition - - self.Tasks = {} - - return self -end - ---- FSM function for a MISSION --- @param #MISSION self --- @param #string Event --- @param #string From --- @param #string To -function MISSION:onbeforeComplete( From, Event, To ) - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if not Task:IsStateSuccess() and not Task:IsStateFailed() and not Task:IsStateAborted() and not Task:IsStateCancelled() then - return false -- Mission cannot be completed. Other Tasks are still active. - end - end - return true -- Allow Mission completion. -end - ---- FSM function for a MISSION --- @param #MISSION self --- @param #string Event --- @param #string From --- @param #string To -function MISSION:onenterCompleted( From, Event, To ) - - self:GetCommandCenter():MessageToCoalition( "Mission " .. self:GetName() .. " has been completed! Good job guys!" ) -end - ---- Gets the mission name. --- @param #MISSION self --- @return #MISSION self -function MISSION:GetName() - return self.Name -end - ---- Add a Unit to join the Mission. --- For each Task within the Mission, the Unit is joined with the Task. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:JoinUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAdded = false - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:JoinUnit( PlayerUnit ) then - PlayerUnitAdded = true - end - end - - return PlayerUnitAdded -end - ---- Aborts a PlayerUnit from the Mission. --- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:AbortUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitRemoved = false - - for TaskID, Task in pairs( self:GetTasks() ) do - if Task:AbortUnit( PlayerUnit ) then - PlayerUnitRemoved = true - end - end - - return PlayerUnitRemoved -end - ---- Handles a crash of a PlayerUnit from the Mission. --- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player crashing. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:CrashUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitRemoved = false - - for TaskID, Task in pairs( self:GetTasks() ) do - if Task:CrashUnit( PlayerUnit ) then - PlayerUnitRemoved = true - end - end - - return PlayerUnitRemoved -end - ---- Add a scoring to the mission. --- @param #MISSION self --- @return #MISSION self -function MISSION:AddScoring( Scoring ) - self.Scoring = Scoring - return self -end - ---- Get the scoring object of a mission. --- @param #MISSION self --- @return #SCORING Scoring -function MISSION:GetScoring() - return self.Scoring -end - ---- Get the groups for which TASKS are given in the mission --- @param #MISSION self --- @return Core.Set#SET_GROUP -function MISSION:GetGroups() - - local SetGroup = SET_GROUP:New() - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - local GroupSet = Task:GetGroups() - GroupSet:ForEachGroup( - function( TaskGroup ) - SetGroup:Add( TaskGroup, TaskGroup ) - end - ) - end - - return SetGroup - -end - - ---- Sets the Planned Task menu. --- @param #MISSION self -function MISSION:SetMenu() - self:F() - - for _, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Task:SetMenu() - end -end - ---- Removes the Planned Task menu. --- @param #MISSION self -function MISSION:RemoveMenu() - self:F() - - for _, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Task:RemoveMenu() - end -end - - ---- Gets the COMMANDCENTER. --- @param #MISSION self --- @return Tasking.CommandCenter#COMMANDCENTER -function MISSION:GetCommandCenter() - return self.CommandCenter -end - ---- Sets the Assigned Task menu. --- @param #MISSION self --- @param Tasking.Task#TASK Task --- @param #string MenuText The menu text. --- @return #MISSION self -function MISSION:SetAssignedMenu( Task ) - - for _, Task in pairs( self.Tasks ) do - local Task = Task -- Tasking.Task#TASK - Task:RemoveMenu() - Task:SetAssignedMenu() - end - -end - ---- Removes a Task menu. --- @param #MISSION self --- @param Tasking.Task#TASK Task --- @return #MISSION self -function MISSION:RemoveTaskMenu( Task ) - - Task:RemoveMenu() -end - - ---- Gets the mission menu for the coalition. --- @param #MISSION self --- @param Wrapper.Group#GROUP TaskGroup --- @return Core.Menu#MENU_COALITION self -function MISSION:GetMissionMenu( TaskGroup ) - - local CommandCenter = self:GetCommandCenter() - local CommandCenterMenu = CommandCenter.CommandCenterMenu - - local MissionName = self:GetName() - - local TaskGroupName = TaskGroup:GetName() - local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ) - - return MissionMenu -end - - ---- Clears the mission menu for the coalition. --- @param #MISSION self --- @return #MISSION self -function MISSION:ClearMissionMenu() - self.MissionMenu:Remove() - self.MissionMenu = nil -end - ---- Get the TASK identified by the TaskNumber from the Mission. This function is useful in GoalFunctions. --- @param #string TaskName The Name of the @{Task} within the @{Mission}. --- @return Tasking.Task#TASK The Task --- @return #nil Returns nil if no task was found. -function MISSION:GetTask( TaskName ) - self:F( { TaskName } ) - - return self.Tasks[TaskName] -end - - ---- Register a @{Task} to be completed within the @{Mission}. --- Note that there can be multiple @{Task}s registered to be completed. --- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return Tasking.Task#TASK The task added. -function MISSION:AddTask( Task ) - - local TaskName = Task:GetTaskName() - self:F( TaskName ) - - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - self.Tasks[TaskName] = Task - - self:GetCommandCenter():SetMenu() - - return Task -end - ---- Removes a @{Task} to be completed within the @{Mission}. --- Note that there can be multiple @{Task}s registered to be completed. --- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return #nil The cleaned Task reference. -function MISSION:RemoveTask( Task ) - - local TaskName = Task:GetTaskName() - - self:F( TaskName ) - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - -- Ensure everything gets garbarge collected. - self.Tasks[TaskName] = nil - Task = nil - - collectgarbage() - - self:GetCommandCenter():SetMenu() - - return nil -end - ---- Return the next @{Task} ID to be completed within the @{Mission}. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return Tasking.Task#TASK The task added. -function MISSION:GetNextTaskID( Task ) - - local TaskName = Task:GetTaskName() - self:F( TaskName ) - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1 - - return self.Tasks[TaskName].n -end - - - ---- old stuff - ---- Returns if a Mission has completed. --- @return bool -function MISSION:IsCompleted() - self:F() - return self.MissionStatus == "ACCOMPLISHED" -end - ---- Set a Mission to completed. -function MISSION:Completed() - self:F() - self.MissionStatus = "ACCOMPLISHED" - self:StatusToClients() -end - ---- Returns if a Mission is ongoing. --- treturn bool -function MISSION:IsOngoing() - self:F() - return self.MissionStatus == "ONGOING" -end - ---- Set a Mission to ongoing. -function MISSION:Ongoing() - self:F() - self.MissionStatus = "ONGOING" - --self:StatusToClients() -end - ---- Returns if a Mission is pending. --- treturn bool -function MISSION:IsPending() - self:F() - return self.MissionStatus == "PENDING" -end - ---- Set a Mission to pending. -function MISSION:Pending() - self:F() - self.MissionStatus = "PENDING" - self:StatusToClients() -end - ---- Returns if a Mission has failed. --- treturn bool -function MISSION:IsFailed() - self:F() - return self.MissionStatus == "FAILED" -end - ---- Set a Mission to failed. -function MISSION:Failed() - self:F() - self.MissionStatus = "FAILED" - self:StatusToClients() -end - ---- Send the status of the MISSION to all Clients. -function MISSION:StatusToClients() - self:F() - if self.MissionReportFlash then - for ClientID, Client in pairs( self._Clients ) do - Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, "Mission Command: Mission Status") - end - end -end - -function MISSION:HasGroup( TaskGroup ) - local Has = false - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:HasGroup( TaskGroup ) then - Has = true - break - end - end - - return Has -end - ---- Create a summary report of the Mission (one line). --- @param #MISSION self --- @return #string -function MISSION:ReportSummary() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:IsStateSuccess() or Task:IsStateFailed() then - else - TasksRemaining = TasksRemaining + 1 - end - end - - Report:Add( "Mission " .. Name .. " - " .. Status .. " - " .. TasksRemaining .. " tasks remaining." ) - - return Report:Text() -end - ---- Create a overview report of the Mission (multiple lines). --- @param #MISSION self --- @return #string -function MISSION:ReportOverview() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Report:Add( "- " .. Task:ReportSummary() ) - end - - return Report:Text() -end - ---- Create a detailed report of the Mission, listing all the details of the Task. --- @param #MISSION self --- @return #string -function MISSION:ReportDetails() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Report:Add( Task:ReportDetails() ) - end - - return Report:Text() -end - ---- Report the status of all MISSIONs to all active Clients. -function MISSION:ReportToAll() - self:F() - - local AlivePlayers = '' - for ClientID, Client in pairs( self._Clients ) do - if Client:GetDCSGroup() then - if Client:GetClientGroupDCSUnit() then - if Client:GetClientGroupDCSUnit():getLife() > 0.0 then - if AlivePlayers == '' then - AlivePlayers = ' Players: ' .. Client:GetClientGroupDCSUnit():getPlayerName() - else - AlivePlayers = AlivePlayers .. ' / ' .. Client:GetClientGroupDCSUnit():getPlayerName() - end - end - end - end - end - local Tasks = self:GetTasks() - local TaskText = "" - for TaskID, TaskData in pairs( Tasks ) do - TaskText = TaskText .. " - Task " .. TaskID .. ": " .. TaskData.Name .. ": " .. TaskData:GetGoalProgress() .. "\n" - end - MESSAGE:New( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. ' ( ' .. self.MissionPriority .. ' mission )' .. AlivePlayers .. "\n" .. TaskText:gsub("\n$",""), 10, "Mission Command: Mission Report" ):ToAll() -end - - ---- Add a goal function to a MISSION. Goal functions are called when a @{TASK} within a mission has been completed. --- @param function GoalFunction is the function defined by the mission designer to evaluate whether a certain goal has been reached after a @{TASK} finishes within the @{MISSION}. A GoalFunction must accept 2 parameters: Mission, Client, which contains the current MISSION object and the current CLIENT object respectively. --- @usage --- PatriotActivation = { --- { "US SAM Patriot Zerti", false }, --- { "US SAM Patriot Zegduleti", false }, --- { "US SAM Patriot Gvleti", false } --- } --- --- function DeployPatriotTroopsGoal( Mission, Client ) --- --- --- -- Check if the cargo is all deployed for mission success. --- for CargoID, CargoData in pairs( Mission._Cargos ) do --- if Group.getByName( CargoData.CargoGroupName ) then --- CargoGroup = Group.getByName( CargoData.CargoGroupName ) --- if CargoGroup then --- -- Check if the cargo is ready to activate --- CurrentLandingZoneID = routines.IsUnitInZones( CargoGroup:getUnits()[1], Mission:GetTask( 2 ).LandingZones ) -- The second task is the Deploytask to measure mission success upon --- if CurrentLandingZoneID then --- if PatriotActivation[CurrentLandingZoneID][2] == false then --- -- Now check if this is a new Mission Task to be completed... --- trigger.action.setGroupAIOn( Group.getByName( PatriotActivation[CurrentLandingZoneID][1] ) ) --- PatriotActivation[CurrentLandingZoneID][2] = true --- MessageToBlue( "Mission Command: Message to all airborne units! The " .. PatriotActivation[CurrentLandingZoneID][1] .. " is armed. Our air defenses are now stronger.", 60, "BLUE/PatriotDefense" ) --- MessageToRed( "Mission Command: Our satellite systems are detecting additional NATO air defenses. To all airborne units: Take care!!!", 60, "RED/PatriotDefense" ) --- Mission:GetTask( 2 ):AddGoalCompletion( "Patriots activated", PatriotActivation[CurrentLandingZoneID][1], 1 ) -- Register Patriot activation as part of mission goal. --- end --- end --- end --- end --- end --- end --- --- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' ) --- Mission:AddGoalFunction( DeployPatriotTroopsGoal ) -function MISSION:AddGoalFunction( GoalFunction ) - self:F() - self.GoalFunction = GoalFunction -end - ---- Register a new @{CLIENT} to participate within the mission. --- @param CLIENT Client is the @{CLIENT} object. The object must have been instantiated with @{CLIENT:New}. --- @return CLIENT --- @usage --- Add a number of Client objects to the Mission. --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*HOT-Deploy Troops 1', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*RAMP-Deploy Troops 3', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*HOT-Deploy Troops 2', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*RAMP-Deploy Troops 4', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) -function MISSION:AddClient( Client ) - self:F( { Client } ) - - local Valid = true - - if Valid then - self._Clients[Client.ClientName] = Client - end - - return Client -end - ---- Find a @{CLIENT} object within the @{MISSION} by its ClientName. --- @param CLIENT ClientName is a string defining the Client Group as defined within the ME. --- @return CLIENT --- @usage --- -- Seach for Client "Bomber" within the Mission. --- local BomberClient = Mission:FindClient( "Bomber" ) -function MISSION:FindClient( ClientName ) - self:F( { self._Clients[ClientName] } ) - return self._Clients[ClientName] -end - - ---- Get all the TASKs from the Mission. This function is useful in GoalFunctions. --- @return {TASK,...} Structure of TASKS with the @{TASK} number as the key. --- @usage --- -- Get Tasks from the Mission. --- Tasks = Mission:GetTasks() --- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) -function MISSION:GetTasks() - self:F() - - return self.Tasks -end - - ---[[ - _TransportExecuteStage: Defines the different stages of Transport unload/load execution. This table is internal and is used to control the validity of Transport load/unload timing. - - - _TransportExecuteStage.EXECUTING - - _TransportExecuteStage.SUCCESS - - _TransportExecuteStage.FAILED - ---]] -_TransportExecuteStage = { - NONE = 0, - EXECUTING = 1, - SUCCESS = 2, - FAILED = 3 -} - - ---- The MISSIONSCHEDULER is an OBJECT and is the main scheduler of ALL active MISSIONs registered within this scheduler. It's workings are considered internal and is automatically created when the Mission.lua file is included. --- @type MISSIONSCHEDULER --- @field #MISSIONSCHEDULER.MISSIONS Missions -MISSIONSCHEDULER = { - Missions = {}, - MissionCount = 0, - TimeIntervalCount = 0, - TimeIntervalShow = 150, - TimeSeconds = 14400, - TimeShow = 5 -} - ---- @type MISSIONSCHEDULER.MISSIONS --- @list <#MISSION> Mission - ---- This is the main MISSIONSCHEDULER Scheduler function. It is considered internal and is automatically created when the Mission.lua file is included. -function MISSIONSCHEDULER.Scheduler() - - - -- loop through the missions in the TransportTasks - for MissionName, MissionData in pairs( MISSIONSCHEDULER.Missions ) do - - local Mission = MissionData -- #MISSION - - if not Mission:IsCompleted() then - - -- This flag will monitor if for this mission, there are clients alive. If this flag is still false at the end of the loop, the mission status will be set to Pending (if not Failed or Completed). - local ClientsAlive = false - - for ClientID, ClientData in pairs( Mission._Clients ) do - - local Client = ClientData -- Wrapper.Client#CLIENT - - if Client:IsAlive() then - - -- There is at least one Client that is alive... So the Mission status is set to Ongoing. - ClientsAlive = true - - -- If this Client was not registered as Alive before: - -- 1. We register the Client as Alive. - -- 2. We initialize the Client Tasks and make a link to the original Mission Task. - -- 3. We initialize the Cargos. - -- 4. We flag the Mission as Ongoing. - if not Client.ClientAlive then - Client.ClientAlive = true - Client.ClientBriefingShown = false - for TaskNumber, Task in pairs( Mission._Tasks ) do - -- Note that this a deepCopy. Each client must have their own Tasks with own Stages!!! - Client._Tasks[TaskNumber] = routines.utils.deepCopy( Mission._Tasks[TaskNumber] ) - -- Each MissionTask must point to the original Mission. - Client._Tasks[TaskNumber].MissionTask = Mission._Tasks[TaskNumber] - Client._Tasks[TaskNumber].Cargos = Mission._Tasks[TaskNumber].Cargos - Client._Tasks[TaskNumber].LandingZones = Mission._Tasks[TaskNumber].LandingZones - end - - Mission:Ongoing() - end - - - -- For each Client, check for each Task the state and evolve the mission. - -- This flag will indicate if the Task of the Client is Complete. - local TaskComplete = false - - for TaskNumber, Task in pairs( Client._Tasks ) do - - if not Task.Stage then - Task:SetStage( 1 ) - end - - - local TransportTime = timer.getTime() - - if not Task:IsDone() then - - if Task:Goal() then - Task:ShowGoalProgress( Mission, Client ) - end - - --env.info( 'Scheduler: Mission = ' .. Mission.Name .. ' / Client = ' .. Client.ClientName .. ' / Task = ' .. Task.Name .. ' / Stage = ' .. Task.ActiveStage .. ' - ' .. Task.Stage.Name .. ' - ' .. Task.Stage.StageType ) - - -- Action - if Task:StageExecute() then - Task.Stage:Execute( Mission, Client, Task ) - end - - -- Wait until execution is finished - if Task.ExecuteStage == _TransportExecuteStage.EXECUTING then - Task.Stage:Executing( Mission, Client, Task ) - end - - -- Validate completion or reverse to earlier stage - if Task.Time + Task.Stage.WaitTime <= TransportTime then - Task:SetStage( Task.Stage:Validate( Mission, Client, Task ) ) - end - - if Task:IsDone() then - --env.info( 'Scheduler: Mission '.. Mission.Name .. ' Task ' .. Task.Name .. ' Stage ' .. Task.Stage.Name .. ' done. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) ) - TaskComplete = true -- when a task is not yet completed, a mission cannot be completed - - else - -- break only if this task is not yet done, so that future task are not yet activated. - TaskComplete = false -- when a task is not yet completed, a mission cannot be completed - --env.info( 'Scheduler: Mission "'.. Mission.Name .. '" Task "' .. Task.Name .. '" Stage "' .. Task.Stage.Name .. '" break. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) ) - break - end - - if TaskComplete then - - if Mission.GoalFunction ~= nil then - Mission.GoalFunction( Mission, Client ) - end - if MISSIONSCHEDULER.Scoring then - MISSIONSCHEDULER.Scoring:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) - end - --- if not Mission:IsCompleted() then --- end - end - end - end - - local MissionComplete = true - for TaskNumber, Task in pairs( Mission._Tasks ) do - if Task:Goal() then --- Task:ShowGoalProgress( Mission, Client ) - if Task:IsGoalReached() then - else - MissionComplete = false - end - else - MissionComplete = false -- If there is no goal, the mission should never be ended. The goal status will be set somewhere else. - end - end - - if MissionComplete then - Mission:Completed() - if MISSIONSCHEDULER.Scoring then - MISSIONSCHEDULER.Scoring:_AddMissionScore( Mission.Name, 100 ) - end - else - if TaskComplete then - -- Reset for new tasking of active client - Client.ClientAlive = false -- Reset the client tasks. - end - end - - - else - if Client.ClientAlive then - env.info( 'Scheduler: Client "' .. Client.ClientName .. '" is inactive.' ) - Client.ClientAlive = false - - -- This is tricky. If we sanitize Client._Tasks before sanitizing Client._Tasks[TaskNumber].MissionTask, then the original MissionTask will be sanitized, and will be lost within the garbage collector. - -- So first sanitize Client._Tasks[TaskNumber].MissionTask, after that, sanitize only the whole _Tasks structure... - --Client._Tasks[TaskNumber].MissionTask = nil - --Client._Tasks = nil - end - end - end - - -- If all Clients of this Mission are not activated, then the Mission status needs to be put back into Pending status. - -- But only if the Mission was Ongoing. In case the Mission is Completed or Failed, the Mission status may not be changed. In these cases, this will be the last run of this Mission in the Scheduler. - if ClientsAlive == false then - if Mission:IsOngoing() then - -- Mission status back to pending... - Mission:Pending() - end - end - end - - Mission:StatusToClients() - - if Mission:ReportTrigger() then - Mission:ReportToAll() - end - end - - return true -end - ---- Start the MISSIONSCHEDULER. -function MISSIONSCHEDULER.Start() - if MISSIONSCHEDULER ~= nil then - --MISSIONSCHEDULER.SchedulerId = routines.scheduleFunction( MISSIONSCHEDULER.Scheduler, { }, 0, 2 ) - MISSIONSCHEDULER.SchedulerId = SCHEDULER:New( nil, MISSIONSCHEDULER.Scheduler, { }, 0, 2 ) - end -end - ---- Stop the MISSIONSCHEDULER. -function MISSIONSCHEDULER.Stop() - if MISSIONSCHEDULER.SchedulerId then - routines.removeFunction(MISSIONSCHEDULER.SchedulerId) - MISSIONSCHEDULER.SchedulerId = nil - end -end - ---- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. --- @param Mission is the MISSION object instantiated by @{MISSION:New}. --- @return MISSION --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) -function MISSIONSCHEDULER.AddMission( Mission ) - MISSIONSCHEDULER.Missions[Mission.Name] = Mission - MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount + 1 - -- Add an overall AI Client for the AI tasks... This AI Client will facilitate the Events in the background for each Task. - --MissionAdd:AddClient( CLIENT:Register( 'AI' ) ) - - return Mission -end - ---- Remove a MISSION from the MISSIONSCHEDULER. --- @param MissionName is the name of the MISSION given at declaration using @{AddMission}. --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) --- --- -- Now remove the Mission. --- MISSIONSCHEDULER:RemoveMission( 'Russia Transport Troops SA-6' ) -function MISSIONSCHEDULER.RemoveMission( MissionName ) - MISSIONSCHEDULER.Missions[MissionName] = nil - MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount - 1 -end - ---- Find a MISSION within the MISSIONSCHEDULER. --- @param MissionName is the name of the MISSION given at declaration using @{AddMission}. --- @return MISSION --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) --- --- -- Now find the Mission. --- MissionFind = MISSIONSCHEDULER:FindMission( 'Russia Transport Troops SA-6' ) -function MISSIONSCHEDULER.FindMission( MissionName ) - return MISSIONSCHEDULER.Missions[MissionName] -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsShow( ) - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = true - Mission.MissionReportFlash = false - end -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsFlash( TimeInterval ) - local Count = 0 - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = false - Mission.MissionReportFlash = true - Mission.MissionReportTrigger = timer.getTime() + Count * TimeInterval - Mission.MissionTimeInterval = MISSIONSCHEDULER.MissionCount * TimeInterval - env.info( "TimeInterval = " .. Mission.MissionTimeInterval ) - Count = Count + 1 - end -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsHide( Prm ) - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = false - Mission.MissionReportFlash = false - end -end - ---- Enables a MENU option in the communications menu under F10 to control the status of the active missions. --- This function should be called only once when starting the MISSIONSCHEDULER. -function MISSIONSCHEDULER.ReportMenu() - local ReportMenu = SUBMENU:New( 'Status' ) - local ReportMenuShow = COMMANDMENU:New( 'Show Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsShow, 0 ) - local ReportMenuFlash = COMMANDMENU:New('Flash Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsFlash, 120 ) - local ReportMenuHide = COMMANDMENU:New( 'Hide Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsHide, 0 ) -end - ---- Show the remaining mission time. -function MISSIONSCHEDULER:TimeShow() - self.TimeIntervalCount = self.TimeIntervalCount + 1 - if self.TimeIntervalCount >= self.TimeTriggerShow then - local TimeMsg = string.format("%00d", ( self.TimeSeconds / 60 ) - ( timer.getTime() / 60 )) .. ' minutes left until mission reload.' - MESSAGE:New( TimeMsg, self.TimeShow, "Mission time" ):ToAll() - self.TimeIntervalCount = 0 - end -end - -function MISSIONSCHEDULER:Time( TimeSeconds, TimeIntervalShow, TimeShow ) - - self.TimeIntervalCount = 0 - self.TimeSeconds = TimeSeconds - self.TimeIntervalShow = TimeIntervalShow - self.TimeShow = TimeShow -end - ---- Adds a mission scoring to the game. -function MISSIONSCHEDULER:Scoring( Scoring ) - - self.Scoring = Scoring -end - ---- This module contains the TASK class. --- --- 1) @{#TASK} class, extends @{Core.Base#BASE} --- ============================================ --- 1.1) The @{#TASK} class implements the methods for task orchestration within MOOSE. --- ---------------------------------------------------------------------------------------- --- The class provides a couple of methods to: --- --- * @{#TASK.AssignToGroup}():Assign a task to a group (of players). --- * @{#TASK.AddProcess}():Add a @{Process} to a task. --- * @{#TASK.RemoveProcesses}():Remove a running @{Process} from a running task. --- * @{#TASK.SetStateMachine}():Set a @{Fsm} to a task. --- * @{#TASK.RemoveStateMachine}():Remove @{Fsm} from a task. --- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Fsm} --- * @{#TASK.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK}. --- * @{#TASK.UnAssignFromUnit}(): Unassign the task from a unit. --- --- 1.2) Set and enquire task status (beyond the task state machine processing). --- ---------------------------------------------------------------------------- --- A task needs to implement as a minimum the following task states: --- --- * **Success**: Expresses the successful execution and finalization of the task. --- * **Failed**: Expresses the failure of a task. --- * **Planned**: Expresses that the task is created, but not yet in execution and is not assigned yet. --- * **Assigned**: Expresses that the task is assigned to a Group of players, and that the task is in execution mode. --- --- A task may also implement the following task states: --- --- * **Rejected**: Expresses that the task is rejected by a player, who was requested to accept the task. --- * **Cancelled**: Expresses that the task is cancelled by HQ or through a logical situation where a cancellation of the task is required. --- --- A task can implement more statusses than the ones outlined above. Please consult the documentation of the specific tasks to understand the different status modelled. --- --- The status of tasks can be set by the methods **State** followed by the task status. An example is `StateAssigned()`. --- The status of tasks can be enquired by the methods **IsState** followed by the task status name. An example is `if IsStateAssigned() then`. --- --- 1.3) Add scoring when reaching a certain task status: --- ----------------------------------------------------- --- Upon reaching a certain task status in a task, additional scoring can be given. If the Mission has a scoring system attached, the scores will be added to the mission scoring. --- Use the method @{#TASK.AddScore}() to add scores when a status is reached. --- --- 1.4) Task briefing: --- ------------------- --- A task briefing can be given that is shown to the player when he is assigned to the task. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task - ---- The TASK class --- @type TASK --- @field Core.Scheduler#SCHEDULER TaskScheduler --- @field Tasking.Mission#MISSION Mission --- @field Core.Set#SET_GROUP SetGroup The Set of Groups assigned to the Task --- @field Core.Fsm#FSM_PROCESS FsmTemplate --- @field Tasking.Mission#MISSION Mission --- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter --- @extends Core.Fsm#FSM_TASK -TASK = { - ClassName = "TASK", - TaskScheduler = nil, - ProcessClasses = {}, -- The container of the Process classes that will be used to create and assign new processes for the task to ProcessUnits. - Processes = {}, -- The container of actual process objects instantiated and assigned to ProcessUnits. - Players = nil, - Scores = {}, - Menu = {}, - SetGroup = nil, - FsmTemplate = nil, - Mission = nil, - CommandCenter = nil, -} - ---- FSM PlayerAborted event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerAborted --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he went back to spectators or left the mission. --- @param #string PlayerName The name of the Player. - ---- FSM PlayerCrashed event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerCrashed --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he crashed in the mission. --- @param #string PlayerName The name of the Player. - ---- FSM PlayerDead event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerDead --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he died in the mission. --- @param #string PlayerName The name of the Player. - ---- FSM Fail synchronous event function for TASK. --- Use this event to Fail the Task. --- @function [parent=#TASK] Fail --- @param #TASK self - ---- FSM Fail asynchronous event function for TASK. --- Use this event to Fail the Task. --- @function [parent=#TASK] __Fail --- @param #TASK self - ---- FSM Abort synchronous event function for TASK. --- Use this event to Abort the Task. --- @function [parent=#TASK] Abort --- @param #TASK self - ---- FSM Abort asynchronous event function for TASK. --- Use this event to Abort the Task. --- @function [parent=#TASK] __Abort --- @param #TASK self - ---- FSM Success synchronous event function for TASK. --- Use this event to make the Task a Success. --- @function [parent=#TASK] Success --- @param #TASK self - ---- FSM Success asynchronous event function for TASK. --- Use this event to make the Task a Success. --- @function [parent=#TASK] __Success --- @param #TASK self - ---- FSM Cancel synchronous event function for TASK. --- Use this event to Cancel the Task. --- @function [parent=#TASK] Cancel --- @param #TASK self - ---- FSM Cancel asynchronous event function for TASK. --- Use this event to Cancel the Task. --- @function [parent=#TASK] __Cancel --- @param #TASK self - ---- FSM Replan synchronous event function for TASK. --- Use this event to Replan the Task. --- @function [parent=#TASK] Replan --- @param #TASK self - ---- FSM Replan asynchronous event function for TASK. --- Use this event to Replan the Task. --- @function [parent=#TASK] __Replan --- @param #TASK self - - ---- Instantiates a new TASK. Should never be used. Interface Class. --- @param #TASK self --- @param Tasking.Mission#MISSION Mission The mission wherein the Task is registered. --- @param Core.Set#SET_GROUP SetGroupAssign The set of groups for which the Task can be assigned. --- @param #string TaskName The name of the Task --- @param #string TaskType The type of the Task --- @return #TASK self -function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) - - local self = BASE:Inherit( self, FSM_TASK:New() ) -- Core.Fsm#FSM_TASK - - self:SetStartState( "Planned" ) - self:AddTransition( "Planned", "Assign", "Assigned" ) - self:AddTransition( "Assigned", "AssignUnit", "Assigned" ) - self:AddTransition( "Assigned", "Success", "Success" ) - self:AddTransition( "Assigned", "Fail", "Failed" ) - self:AddTransition( "Assigned", "Abort", "Aborted" ) - self:AddTransition( "Assigned", "Cancel", "Cancelled" ) - self:AddTransition( "*", "PlayerCrashed", "*" ) - self:AddTransition( "*", "PlayerAborted", "*" ) - self:AddTransition( "*", "PlayerDead", "*" ) - self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" ) - - self:E( "New TASK " .. TaskName ) - - self.Processes = {} - self.Fsm = {} - - self.Mission = Mission - self.CommandCenter = Mission:GetCommandCenter() - - self.SetGroup = SetGroupAssign - - self:SetType( TaskType ) - self:SetName( TaskName ) - self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences .. - - self.TaskBriefing = "You are invited for the task: " .. self.TaskName .. "." - - self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() - - -- Handle the birth of new planes within the assigned set. - - - -- Handle when a player crashes ... - -- The Task is UnAssigned from the Unit. - -- When there is no Unit left running the Task, and all of the Players crashed, the Task goes into Failed ... --- self:EventOnCrash( --- --- @param #TASK self --- -- @param Core.Event#EVENTDATA EventData --- function( self, EventData ) --- self:E( "In LeaveUnit" ) --- self:E( { "State", self:GetState() } ) --- if self:IsStateAssigned() then --- local TaskUnit = EventData.IniUnit --- local TaskGroup = EventData.IniUnit:GetGroup() --- self:E( self.SetGroup:IsIncludeObject( TaskGroup ) ) --- if self.SetGroup:IsIncludeObject( TaskGroup ) then --- self:UnAssignFromUnit( TaskUnit ) --- end --- self:MessageToGroups( TaskUnit:GetPlayerName() .. " crashed!, and has aborted Task " .. self:GetName() ) --- end --- end --- ) --- - - Mission:AddTask( self ) - - return self -end - ---- Get the Task FSM Process Template --- @param #TASK self --- @return Core.Fsm#FSM_PROCESS -function TASK:GetUnitProcess() - - return self.FsmTemplate -end - ---- Sets the Task FSM Process Template --- @param #TASK self --- @param Core.Fsm#FSM_PROCESS -function TASK:SetUnitProcess( FsmTemplate ) - - self.FsmTemplate = FsmTemplate -end - ---- Add a PlayerUnit to join the Task. --- For each Group within the Task, the Unit is check if it can join the Task. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of the Task. -function TASK:JoinUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAdded = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task. - -- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader. - if self:IsStatePlanned() or self:IsStateReplanned() then - self:SetMenuForGroup( PlayerGroup ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() ) - end - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:AssignToUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " joined Task " .. self:GetName() ) - end - end - end - - return PlayerUnitAdded -end - ---- Abort a PlayerUnit from a Task. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. -function TASK:AbortUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAborted = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. - -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:UnAssignFromUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " aborted Task " .. self:GetName() ) - self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) - if #PlayerGroup:GetUnits() == 1 then - PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) - self:RemoveMenuForGroup( PlayerGroup ) - end - self:PlayerAborted( PlayerUnit ) - end - end - end - - return PlayerUnitAborted -end - ---- A PlayerUnit crashed in a Task. Abort the Player. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. -function TASK:CrashUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitCrashed = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. - -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:UnAssignFromUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " crashed in Task " .. self:GetName() ) - self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) - if #PlayerGroup:GetUnits() == 1 then - PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) - self:RemoveMenuForGroup( PlayerGroup ) - end - self:PlayerCrashed( PlayerUnit ) - end - end - end - - return PlayerUnitCrashed -end - - - ---- Gets the Mission to where the TASK belongs. --- @param #TASK self --- @return Tasking.Mission#MISSION -function TASK:GetMission() - - return self.Mission -end - - ---- Gets the SET_GROUP assigned to the TASK. --- @param #TASK self --- @return Core.Set#SET_GROUP -function TASK:GetGroups() - return self.SetGroup -end - - - ---- Assign the @{Task}to a @{Group}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK -function TASK:AssignToGroup( TaskGroup ) - self:F2( TaskGroup:GetName() ) - - local TaskGroupName = TaskGroup:GetName() - - TaskGroup:SetState( TaskGroup, "Assigned", self ) - - self:RemoveMenuForGroup( TaskGroup ) - self:SetAssignedMenuForGroup( TaskGroup ) - - local TaskUnits = TaskGroup:GetUnits() - for UnitID, UnitData in pairs( TaskUnits ) do - local TaskUnit = UnitData -- Wrapper.Unit#UNIT - local PlayerName = TaskUnit:GetPlayerName() - self:E(PlayerName) - if PlayerName ~= nil or PlayerName ~= "" then - self:AssignToUnit( TaskUnit ) - end - end - - return self -end - ---- --- @param #TASK self --- @param Wrapper.Group#GROUP FindGroup --- @return #boolean -function TASK:HasGroup( FindGroup ) - - self:GetGroups():FilterOnce() -- Ensure that the filter is updated. - return self:GetGroups():IsIncludeObject( FindGroup ) - -end - ---- Assign the @{Task} to an alive @{Unit}. --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:AssignToUnit( TaskUnit ) - self:F( TaskUnit:GetName() ) - - local FsmTemplate = self:GetUnitProcess() - - -- Assign a new FsmUnit to TaskUnit. - local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Core.Fsm#FSM_PROCESS - self:E({"Address FsmUnit", tostring( FsmUnit ) } ) - - FsmUnit:SetStartState( "Planned" ) - FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow. - - return self -end - ---- UnAssign the @{Task} from an alive @{Unit}. --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:UnAssignFromUnit( TaskUnit ) - self:F( TaskUnit ) - - self:RemoveStateMachine( TaskUnit ) - - return self -end - ---- Send a message of the @{Task} to the assigned @{Group}s. --- @param #TASK self -function TASK:MessageToGroups( Message ) - self:F( { Message = Message } ) - - local Mission = self:GetMission() - local CC = Mission:GetCommandCenter() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - local TaskGroup = TaskGroup -- Wrapper.Group#GROUP - CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() ) - end -end - - ---- Send the briefng message of the @{Task} to the assigned @{Group}s. --- @param #TASK self -function TASK:SendBriefingToAssignedGroups() - self:F2() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - - if self:IsAssignedToGroup( TaskGroup ) then - TaskGroup:Message( self.TaskBriefing, 60 ) - end - end -end - - ---- Assign the @{Task} from the @{Group}s. --- @param #TASK self -function TASK:UnAssignFromGroups() - self:F2() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - - TaskGroup:SetState( TaskGroup, "Assigned", nil ) - - self:RemoveMenuForGroup( TaskGroup ) - - local TaskUnits = TaskGroup:GetUnits() - for UnitID, UnitData in pairs( TaskUnits ) do - local TaskUnit = UnitData -- Wrapper.Unit#UNIT - local PlayerName = TaskUnit:GetPlayerName() - if PlayerName ~= nil or PlayerName ~= "" then - self:UnAssignFromUnit( TaskUnit ) - end - end - end -end - ---- Returns if the @{Task} is assigned to the Group. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #boolean -function TASK:IsAssignedToGroup( TaskGroup ) - - local TaskGroupName = TaskGroup:GetName() - - if self:IsStateAssigned() then - if TaskGroup:GetState( TaskGroup, "Assigned" ) == self then - return true - end - end - - return false -end - ---- Returns if the @{Task} has still alive and assigned Units. --- @param #TASK self --- @return #boolean -function TASK:HasAliveUnits() - self:F() - - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if self:IsStateAssigned() then - if self:IsAssignedToGroup( TaskGroup ) then - for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do - if TaskUnit:IsAlive() then - self:T( { HasAliveUnits = true } ) - return true - end - end - end - end - end - - self:T( { HasAliveUnits = false } ) - return false -end - ---- Set the menu options of the @{Task} to all the groups in the SetGroup. --- @param #TASK self -function TASK:SetMenu() - self:F() - - self.SetGroup:Flush() - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if self:IsStatePlanned() or self:IsStateReplanned() then - self:SetMenuForGroup( TaskGroup ) - end - end -end - - ---- Remove the menu options of the @{Task} to all the groups in the SetGroup. --- @param #TASK self --- @return #TASK self -function TASK:RemoveMenu() - - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - self:RemoveMenuForGroup( TaskGroup ) - end -end - - ---- Set the Menu for a Group --- @param #TASK self -function TASK:SetMenuForGroup( TaskGroup ) - - if not self:IsAssignedToGroup( TaskGroup ) then - self:SetPlannedMenuForGroup( TaskGroup, self:GetTaskName() ) - else - self:SetAssignedMenuForGroup( TaskGroup ) - end -end - - ---- Set the planned menu option of the @{Task}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @param #string MenuText The menu text. --- @return #TASK self -function TASK:SetPlannedMenuForGroup( TaskGroup, MenuText ) - self:E( TaskGroup:GetName() ) - - local Mission = self:GetMission() - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - - local TaskType = self:GetType() - local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, MissionMenu ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, MenuText, TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ) - - return self -end - ---- Set the assigned menu options of the @{Task}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK self -function TASK:SetAssignedMenuForGroup( TaskGroup ) - self:E( TaskGroup:GetName() ) - - local Mission = self:GetMission() - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - - self:E( { MissionMenu = MissionMenu } ) - - local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Task Status", MissionMenu, self.MenuTaskStatus, { self = self, TaskGroup = TaskGroup } ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Abort Task", MissionMenu, self.MenuTaskAbort, { self = self, TaskGroup = TaskGroup } ) - - return self -end - ---- Remove the menu option of the @{Task} for a @{Group}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK self -function TASK:RemoveMenuForGroup( TaskGroup ) - - local Mission = self:GetMission() - local MissionName = Mission:GetName() - - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - MissionMenu:Remove() -end - -function TASK.MenuAssignToGroup( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - self:E( "Assigned menu selected") - - self:AssignToGroup( TaskGroup ) -end - -function TASK.MenuTaskStatus( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - --self:AssignToGroup( TaskGroup ) -end - -function TASK.MenuTaskAbort( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - --self:AssignToGroup( TaskGroup ) -end - - - ---- Returns the @{Task} name. --- @param #TASK self --- @return #string TaskName -function TASK:GetTaskName() - return self.TaskName -end - - - - ---- Get the default or currently assigned @{Process} template with key ProcessName. --- @param #TASK self --- @param #string ProcessName --- @return Core.Fsm#FSM_PROCESS -function TASK:GetProcessTemplate( ProcessName ) - - local ProcessTemplate = self.ProcessClasses[ProcessName] - - return ProcessTemplate -end - - - --- TODO: Obscolete? ---- Fail processes from @{Task} with key @{Unit} --- @param #TASK self --- @param #string TaskUnitName --- @return #TASK self -function TASK:FailProcesses( TaskUnitName ) - - for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do - local Process = ProcessData - Process.Fsm:Fail() - end -end - ---- Add a FiniteStateMachine to @{Task} with key Task@{Unit} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:SetStateMachine( TaskUnit, Fsm ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - self.Fsm[TaskUnit] = Fsm - - return Fsm -end - ---- Remove FiniteStateMachines from @{Task} with key Task@{Unit} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:RemoveStateMachine( TaskUnit ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - self.Fsm[TaskUnit] = nil - collectgarbage() - self:T( "Garbage Collected, Processes should be finalized now ...") -end - ---- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:HasStateMachine( TaskUnit ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - return ( self.Fsm[TaskUnit] ~= nil ) -end - - ---- Gets the Scoring of the task --- @param #TASK self --- @return Functional.Scoring#SCORING Scoring -function TASK:GetScoring() - return self.Mission:GetScoring() -end - - ---- Gets the Task Index, which is a combination of the Task type, the Task name. --- @param #TASK self --- @return #string The Task ID -function TASK:GetTaskIndex() - - local TaskType = self:GetType() - local TaskName = self:GetName() - - return TaskType .. "." .. TaskName -end - ---- Sets the Name of the Task --- @param #TASK self --- @param #string TaskName -function TASK:SetName( TaskName ) - self.TaskName = TaskName -end - ---- Gets the Name of the Task --- @param #TASK self --- @return #string The Task Name -function TASK:GetName() - return self.TaskName -end - ---- Sets the Type of the Task --- @param #TASK self --- @param #string TaskType -function TASK:SetType( TaskType ) - self.TaskType = TaskType -end - ---- Gets the Type of the Task --- @param #TASK self --- @return #string TaskType -function TASK:GetType() - return self.TaskType -end - ---- Sets the ID of the Task --- @param #TASK self --- @param #string TaskID -function TASK:SetID( TaskID ) - self.TaskID = TaskID -end - ---- Gets the ID of the Task --- @param #TASK self --- @return #string TaskID -function TASK:GetID() - return self.TaskID -end - - ---- Sets a @{Task} to status **Success**. --- @param #TASK self -function TASK:StateSuccess() - self:SetState( self, "State", "Success" ) - return self -end - ---- Is the @{Task} status **Success**. --- @param #TASK self -function TASK:IsStateSuccess() - return self:Is( "Success" ) -end - ---- Sets a @{Task} to status **Failed**. --- @param #TASK self -function TASK:StateFailed() - self:SetState( self, "State", "Failed" ) - return self -end - ---- Is the @{Task} status **Failed**. --- @param #TASK self -function TASK:IsStateFailed() - return self:Is( "Failed" ) -end - ---- Sets a @{Task} to status **Planned**. --- @param #TASK self -function TASK:StatePlanned() - self:SetState( self, "State", "Planned" ) - return self -end - ---- Is the @{Task} status **Planned**. --- @param #TASK self -function TASK:IsStatePlanned() - return self:Is( "Planned" ) -end - ---- Sets a @{Task} to status **Assigned**. --- @param #TASK self -function TASK:StateAssigned() - self:SetState( self, "State", "Assigned" ) - return self -end - ---- Is the @{Task} status **Assigned**. --- @param #TASK self -function TASK:IsStateAssigned() - return self:Is( "Assigned" ) -end - ---- Sets a @{Task} to status **Hold**. --- @param #TASK self -function TASK:StateHold() - self:SetState( self, "State", "Hold" ) - return self -end - ---- Is the @{Task} status **Hold**. --- @param #TASK self -function TASK:IsStateHold() - return self:Is( "Hold" ) -end - ---- Sets a @{Task} to status **Replanned**. --- @param #TASK self -function TASK:StateReplanned() - self:SetState( self, "State", "Replanned" ) - return self -end - ---- Is the @{Task} status **Replanned**. --- @param #TASK self -function TASK:IsStateReplanned() - return self:Is( "Replanned" ) -end - ---- Gets the @{Task} status. --- @param #TASK self -function TASK:GetStateString() - return self:GetState( self, "State" ) -end - ---- Sets a @{Task} briefing. --- @param #TASK self --- @param #string TaskBriefing --- @return #TASK self -function TASK:SetBriefing( TaskBriefing ) - self.TaskBriefing = TaskBriefing - return self -end - - - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterAssigned( From, Event, To ) - - self:E("Task Assigned") - - self:MessageToGroups( "Task " .. self:GetName() .. " has been assigned to your group." ) - self:GetMission():__Start() -end - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterSuccess( From, Event, To ) - - self:E( "Task Success" ) - - self:MessageToGroups( "Task " .. self:GetName() .. " is successful! Good job!" ) - self:UnAssignFromGroups() - - self:GetMission():__Complete() - -end - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterAborted( From, Event, To ) - - self:E( "Task Aborted" ) - - self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been aborted! Task may be replanned." ) - - self:UnAssignFromGroups() -end - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterFailed( From, Event, To ) - - self:E( "Task Failed" ) - - self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has failed!" ) - - self:UnAssignFromGroups() -end - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onstatechange( From, Event, To ) - - if self:IsTrace() then - MESSAGE:New( "@ Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() - end - - if self.Scores[To] then - local Scoring = self:GetScoring() - if Scoring then - self:E( { self.Scores[To].ScoreText, self.Scores[To].Score } ) - Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score ) - end - end - -end - -do -- Reporting - ---- Create a summary report of the Task. --- List the Task Name and Status --- @param #TASK self --- @return #string -function TASK:ReportSummary() - - local Report = REPORT:New() - - -- List the name of the Task. - local Name = self:GetName() - - -- Determine the status of the Task. - local State = self:GetState() - - Report:Add( "Task " .. Name .. " - State '" .. State ) - - return Report:Text() -end - - ---- Create a detailed report of the Task. --- List the Task Status, and the Players assigned to the Task. --- @param #TASK self --- @return #string -function TASK:ReportDetails() - - local Report = REPORT:New() - - -- List the name of the Task. - local Name = self:GetName() - - -- Determine the status of the Task. - local State = self:GetState() - - - -- Loop each Unit active in the Task, and find Player Names. - local PlayerNames = {} - for PlayerGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do - local Player = PlayerGroup -- Wrapper.Group#GROUP - for PlayerUnitID, PlayerUnit in pairs( PlayerGroup:GetUnits() ) do - local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT - if PlayerUnit and PlayerUnit:IsAlive() then - local PlayerName = PlayerUnit:GetPlayerName() - PlayerNames[#PlayerNames+1] = PlayerName - end - end - local PlayerNameText = table.concat( PlayerNames, ", " ) - Report:Add( "Task " .. Name .. " - State '" .. State .. "' - Players " .. PlayerNameText ) - end - - -- Loop each Process in the Task, and find Reporting Details. - - return Report:Text() -end - - -end -- Reporting --- This module contains the DETECTION_MANAGER class and derived classes. --- --- === --- --- 1) @{Tasking.DetectionManager#DETECTION_MANAGER} class, extends @{Core.Base#BASE} --- ==================================================================== --- The @{Tasking.DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. --- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. --- --- 1.1) DETECTION_MANAGER constructor: --- ----------------------------------- --- * @{Tasking.DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. --- --- 1.2) DETECTION_MANAGER reporting: --- --------------------------------- --- Derived DETECTION_MANAGER classes will reports detected units using the method @{Tasking.DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. --- --- The time interval in seconds of the reporting can be changed using the methods @{Tasking.DetectionManager#DETECTION_MANAGER.SetReportInterval}(). --- To control how long a reporting message is displayed, use @{Tasking.DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}(). --- Derived classes need to implement the method @{Tasking.DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. --- --- Reporting can be started and stopped using the methods @{Tasking.DetectionManager#DETECTION_MANAGER.StartReporting}() and @{Tasking.DetectionManager#DETECTION_MANAGER.StopReporting}() respectively. --- If an ad-hoc report is requested, use the method @{Tasking.DetectionManager#DETECTION_MANAGER#ReportNow}(). --- --- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. --- --- === --- --- 2) @{Tasking.DetectionManager#DETECTION_REPORTING} class, extends @{Tasking.DetectionManager#DETECTION_MANAGER} --- ========================================================================================= --- The @{Tasking.DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Tasking.DetectionManager#DETECTION_MANAGER} class. --- --- 2.1) DETECTION_REPORTING constructor: --- ------------------------------- --- The @{Tasking.DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance. --- --- === --- --- 3) @{#DETECTION_DISPATCHER} class, extends @{#DETECTION_MANAGER} --- ================================================================ --- The @{#DETECTION_DISPATCHER} class implements the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of FAC (groups). --- The FAC will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. --- Find a summary below describing for which situation a task type is created: --- --- * **CAS Task**: Is created when there are enemy ground units within range of the FAC, while there are friendly units in the FAC perimeter. --- * **BAI Task**: Is created when there are enemy ground units within range of the FAC, while there are NO other friendly units within the FAC perimeter. --- * **SEAD Task**: Is created when there are enemy ground units wihtin range of the FAC, with air search radars. --- --- Other task types will follow... --- --- 3.1) DETECTION_DISPATCHER constructor: --- -------------------------------------- --- The @{#DETECTION_DISPATCHER.New}() method creates a new DETECTION_DISPATCHER instance. --- --- === --- --- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing --- ### Author: FlightControl - Framework Design & Programming --- --- @module DetectionManager - -do -- DETECTION MANAGER - - --- DETECTION_MANAGER class. - -- @type DETECTION_MANAGER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @extends Base#BASE - DETECTION_MANAGER = { - ClassName = "DETECTION_MANAGER", - SetGroup = nil, - Detection = nil, - } - - --- FAC constructor. - -- @param #DETECTION_MANAGER self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:New( SetGroup, Detection ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) -- Functional.Detection#DETECTION_MANAGER - - self.SetGroup = SetGroup - self.Detection = Detection - - self:SetReportInterval( 30 ) - self:SetReportDisplayTime( 25 ) - - return self - end - - --- Set the reporting time interval. - -- @param #DETECTION_MANAGER self - -- @param #number ReportInterval The interval in seconds when a report needs to be done. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:SetReportInterval( ReportInterval ) - self:F2() - - self._ReportInterval = ReportInterval - end - - - --- Set the reporting message display time. - -- @param #DETECTION_MANAGER self - -- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:SetReportDisplayTime( ReportDisplayTime ) - self:F2() - - self._ReportDisplayTime = ReportDisplayTime - end - - --- Get the reporting message display time. - -- @param #DETECTION_MANAGER self - -- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. - function DETECTION_MANAGER:GetReportDisplayTime() - self:F2() - - return self._ReportDisplayTime - end - - - - --- Reports the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_MANAGER self - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:ReportDetected( Detection ) - self:F2() - - end - - --- Schedule the FAC reporting. - -- @param #DETECTION_MANAGER self - -- @param #number DelayTime The delay in seconds to wait the reporting. - -- @param #number ReportInterval The repeat interval in seconds for the reporting to happen repeatedly. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:Schedule( DelayTime, ReportInterval ) - self:F2() - - self._ScheduleDelayTime = DelayTime - - self:SetReportInterval( ReportInterval ) - - self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "DetectionManager" }, self._ScheduleDelayTime, self._ReportInterval ) - return self - end - - --- Report the detected @{Wrapper.Unit#UNIT}s detected within the @{Functional.Detection#DETECTION_BASE} object to the @{Set#SET_GROUP}s. - -- @param #DETECTION_MANAGER self - function DETECTION_MANAGER:_FacScheduler( SchedulerName ) - self:F2( { SchedulerName } ) - - return self:ProcessDetected( self.Detection ) - --- self.SetGroup:ForEachGroup( --- --- @param Wrapper.Group#GROUP Group --- function( Group ) --- if Group:IsAlive() then --- return self:ProcessDetected( self.Detection ) --- end --- end --- ) - --- return true - end - -end - - -do -- DETECTION_REPORTING - - --- DETECTION_REPORTING class. - -- @type DETECTION_REPORTING - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @extends #DETECTION_MANAGER - DETECTION_REPORTING = { - ClassName = "DETECTION_REPORTING", - } - - - --- DETECTION_REPORTING constructor. - -- @param #DETECTION_REPORTING self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_AREAS Detection - -- @return #DETECTION_REPORTING self - function DETECTION_REPORTING:New( SetGroup, Detection ) - - -- Inherits from DETECTION_MANAGER - local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_REPORTING - - self:Schedule( 1, 30 ) - return self - end - - --- Creates a string of the detected items in a @{Detection}. - -- @param #DETECTION_MANAGER self - -- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Functional.Detection#DETECTION_BASE} object. - -- @return #DETECTION_MANAGER self - function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet ) - self:F2() - - local MT = {} -- Message Text - local UnitTypes = {} - - for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - if DetectedUnit:IsAlive() then - local UnitType = DetectedUnit:GetTypeName() - - if not UnitTypes[UnitType] then - UnitTypes[UnitType] = 1 - else - UnitTypes[UnitType] = UnitTypes[UnitType] + 1 - end - end - end - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return table.concat( MT, ", " ) - end - - - - --- Reports the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_REPORTING self - -- @param Wrapper.Group#GROUP Group The @{Group} object to where the report needs to go. - -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_BASE} object. - -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. - function DETECTION_REPORTING:ProcessDetected( Group, Detection ) - self:F2( Group ) - - self:E( Group ) - local DetectedMsg = {} - for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do - local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea - DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set ) - end - local FACGroup = Detection:GetDetectionGroups() - FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group ) - - return true - end - -end - -do -- DETECTION_DISPATCHER - - --- DETECTION_DISPATCHER class. - -- @type DETECTION_DISPATCHER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @field Tasking.Mission#MISSION Mission - -- @field Wrapper.Group#GROUP CommandCenter - -- @extends Tasking.DetectionManager#DETECTION_MANAGER - DETECTION_DISPATCHER = { - ClassName = "DETECTION_DISPATCHER", - Mission = nil, - CommandCenter = nil, - Detection = nil, - } - - - --- DETECTION_DISPATCHER constructor. - -- @param #DETECTION_DISPATCHER self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_DISPATCHER self - function DETECTION_DISPATCHER:New( Mission, CommandCenter, SetGroup, Detection ) - - -- Inherits from DETECTION_MANAGER - local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_DISPATCHER - - self.Detection = Detection - self.CommandCenter = CommandCenter - self.Mission = Mission - - self:Schedule( 30 ) - return self - end - - - --- Creates a SEAD task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. - -- @return #nil If there are no targets to be set. - function DETECTION_DISPATCHER:EvaluateSEAD( DetectedArea ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local RadarCount = DetectedSet:HasSEAD() - - if RadarCount > 0 then - - -- Here we're doing something advanced... We're copying the DetectedSet, but making a new Set only with SEADable Radar units in it. - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterHasSEAD() - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Creates a CAS task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateCAS( DetectedArea ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local GroundUnitCount = DetectedSet:HasGroundUnits() - local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea ) - - if GroundUnitCount > 0 and FriendliesNearBy == true then - - -- Copy the Set - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Creates a BAI task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateBAI( DetectedArea, FriendlyCoalition ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local GroundUnitCount = DetectedSet:HasGroundUnits() - local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea ) - - if GroundUnitCount > 0 and FriendliesNearBy == false then - - -- Copy the Set - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Evaluates the removal of the Task from the Mission. - -- Can only occur when the DetectedArea is Changed AND the state of the Task is "Planned". - -- @param #DETECTION_DISPATCHER self - -- @param Tasking.Mission#MISSION Mission - -- @param Tasking.Task#TASK Task - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateRemoveTask( Mission, Task, DetectedArea ) - - if Task then - if Task:IsStatePlanned() and DetectedArea.Changed == true then - self:E( "Removing Tasking: " .. Task:GetTaskName() ) - Task = Mission:RemoveTask( Task ) - end - end - - return Task - end - - - --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_AREAS} object. - -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. - function DETECTION_DISPATCHER:ProcessDetected( Detection ) - self:F2() - - local AreaMsg = {} - local TaskMsg = {} - local ChangeMsg = {} - - local Mission = self.Mission - - --- First we need to the detected targets. - for DetectedAreaID, DetectedAreaData in ipairs( Detection:GetDetectedAreas() ) do - - local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - self:E( { "Targets in DetectedArea", DetectedArea.AreaID, DetectedSet:Count(), tostring( DetectedArea ) } ) - DetectedSet:Flush() - - local AreaID = DetectedArea.AreaID - - -- Evaluate SEAD Tasking - local SEADTask = Mission:GetTask( "SEAD." .. AreaID ) - SEADTask = self:EvaluateRemoveTask( Mission, SEADTask, DetectedArea ) - if not SEADTask then - local TargetSetUnit = self:EvaluateSEAD( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - SEADTask = Mission:AddTask( TASK_SEAD:New( Mission, self.SetGroup, "SEAD." .. AreaID, TargetSetUnit , DetectedZone ) ) - end - end - if SEADTask and SEADTask:IsStatePlanned() then - self:E( "Planned" ) - --SEADTask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. SEADTask:GetStateString() .. " SEAD " .. AreaID .. " - " .. SEADTask.TargetSetUnit:GetUnitTypesText() - end - - -- Evaluate CAS Tasking - local CASTask = Mission:GetTask( "CAS." .. AreaID ) - CASTask = self:EvaluateRemoveTask( Mission, CASTask, DetectedArea ) - if not CASTask then - local TargetSetUnit = self:EvaluateCAS( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - CASTask = Mission:AddTask( TASK_A2G:New( Mission, self.SetGroup, "CAS." .. AreaID, "CAS", TargetSetUnit , DetectedZone, DetectedArea.NearestFAC ) ) - end - end - if CASTask and CASTask:IsStatePlanned() then - --CASTask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. CASTask:GetStateString() .. " CAS " .. AreaID .. " - " .. CASTask.TargetSetUnit:GetUnitTypesText() - end - - -- Evaluate BAI Tasking - local BAITask = Mission:GetTask( "BAI." .. AreaID ) - BAITask = self:EvaluateRemoveTask( Mission, BAITask, DetectedArea ) - if not BAITask then - local TargetSetUnit = self:EvaluateBAI( DetectedArea, self.CommandCenter:GetCoalition() ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - BAITask = Mission:AddTask( TASK_A2G:New( Mission, self.SetGroup, "BAI." .. AreaID, "BAI", TargetSetUnit , DetectedZone, DetectedArea.NearestFAC ) ) - end - end - if BAITask and BAITask:IsStatePlanned() then - --BAITask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. BAITask:GetStateString() .. " BAI " .. AreaID .. " - " .. BAITask.TargetSetUnit:GetUnitTypesText() - end - - if #TaskMsg > 0 then - - local ThreatLevel = Detection:GetTreatLevelA2G( DetectedArea ) - - local DetectedAreaVec3 = DetectedZone:GetVec3() - local DetectedAreaPointVec3 = POINT_VEC3:New( DetectedAreaVec3.x, DetectedAreaVec3.y, DetectedAreaVec3.z ) - local DetectedAreaPointLL = DetectedAreaPointVec3:ToStringLL( 3, true ) - AreaMsg[#AreaMsg+1] = string.format( " - Area #%d - %s - Threat Level [%s] (%2d)", - DetectedAreaID, - DetectedAreaPointLL, - string.rep( "■", ThreatLevel ), - ThreatLevel - ) - - -- Loop through the changes ... - local ChangeText = Detection:GetChangeText( DetectedArea ) - - if ChangeText ~= "" then - ChangeMsg[#ChangeMsg+1] = string.gsub( string.gsub( ChangeText, "\n", "%1 - " ), "^.", " - %1" ) - end - end - - -- OK, so the tasking has been done, now delete the changes reported for the area. - Detection:AcceptChanges( DetectedArea ) - - end - - -- TODO set menus using the HQ coordinator - Mission:GetCommandCenter():SetMenu() - - if #AreaMsg > 0 then - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if not TaskGroup:GetState( TaskGroup, "Assigned" ) then - self.CommandCenter:MessageToGroup( - string.format( "HQ Reporting - Target areas for mission '%s':\nAreas:\n%s\n\nTasks:\n%s\n\nChanges:\n%s ", - self.Mission:GetName(), - table.concat( AreaMsg, "\n" ), - table.concat( TaskMsg, "\n" ), - table.concat( ChangeMsg, "\n" ) - ), self:GetReportDisplayTime(), TaskGroup - ) - end - end - end - - return true - end - -end--- This module contains the TASK_SEAD classes. --- --- 1) @{#TASK_SEAD} class, extends @{Tasking.Task#TASK} --- ================================================= --- The @{#TASK_SEAD} class defines a SEAD task for a @{Set} of Target Units, located at a Target Zone, --- based on the tasking capabilities defined in @{Tasking.Task#TASK}. --- The TASK_SEAD is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: --- --- * **None**: Start of the process --- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. --- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. --- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task_SEAD - - - -do -- TASK_SEAD - - --- The TASK_SEAD class - -- @type TASK_SEAD - -- @field Set#SET_UNIT TargetSetUnit - -- @extends Tasking.Task#TASK - TASK_SEAD = { - ClassName = "TASK_SEAD", - } - - --- Instantiates a new TASK_SEAD. - -- @param #TASK_SEAD self - -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #TASK_SEAD self - function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TargetZone ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, "SEAD" ) ) -- Tasking.Task_SEAD#TASK_SEAD - self:F() - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - local Fsm = self:GetUnitProcess() - - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "Route", Rejected = "Eject" } ) - Fsm:AddProcess ( "Assigned", "Route", ACT_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } ) - Fsm:AddTransition( "Rejected", "Eject", "Planned" ) - Fsm:AddTransition( "Arrived", "Update", "Updated" ) - Fsm:AddProcess ( "Updated", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, "SEAD" ), { Accounted = "Success" } ) - Fsm:AddProcess ( "Updated", "Smoke", ACT_ASSIST_SMOKE_TARGETS_ZONE:New( self.TargetSetUnit, self.TargetZone ) ) - Fsm:AddTransition( "Accounted", "Success", "Success" ) - Fsm:AddTransition( "Failed", "Fail", "Failed" ) - - function Fsm:onenterUpdated( TaskUnit ) - self:E( { self } ) - self:Account() - self:Smoke() - end - --- _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self ) --- _EVENTDISPATCHER:OnDead( self._EventDead, self ) --- _EVENTDISPATCHER:OnCrash( self._EventDead, self ) --- _EVENTDISPATCHER:OnPilotDead( self._EventDead, self ) - - return self - end - - --- @param #TASK_SEAD self - function TASK_SEAD:GetPlannedMenuText() - return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" - end - -end ---- (AI) (SP) (MP) Tasking for Air to Ground Processes. --- --- 1) @{#TASK_A2G} class, extends @{Tasking.Task#TASK} --- ================================================= --- The @{#TASK_A2G} class defines a CAS or BAI task of a @{Set} of Target Units, --- located at a Target Zone, based on the tasking capabilities defined in @{Tasking.Task#TASK}. --- The TASK_A2G is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: --- --- * **None**: Start of the process --- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. --- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. --- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task_A2G - - -do -- TASK_A2G - - --- The TASK_A2G class - -- @type TASK_A2G - -- @extends Tasking.Task#TASK - TASK_A2G = { - ClassName = "TASK_A2G", - } - - --- Instantiates a new TASK_A2G. - -- @param #TASK_A2G self - -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param #string TaskType BAI or CAS - -- @param Set#SET_UNIT UnitSetTargets - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #TASK_A2G self - function TASK_A2G:New( Mission, SetGroup, TaskName, TaskType, TargetSetUnit, TargetZone, FACUnit ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) - self:F() - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - self.FACUnit = FACUnit - - local A2GUnitProcess = self:GetUnitProcess() - - A2GUnitProcess:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( "Attack the Area" ), { Assigned = "Route", Rejected = "Eject" } ) - A2GUnitProcess:AddProcess ( "Assigned", "Route", ACT_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } ) - A2GUnitProcess:AddTransition( "Rejected", "Eject", "Planned" ) - A2GUnitProcess:AddTransition( "Arrived", "Update", "Updated" ) - A2GUnitProcess:AddProcess ( "Updated", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, "Attack" ), { Accounted = "Success" } ) - A2GUnitProcess:AddProcess ( "Updated", "Smoke", ACT_ASSIST_SMOKE_TARGETS_ZONE:New( self.TargetSetUnit, self.TargetZone ) ) - --Fsm:AddProcess ( "Updated", "JTAC", PROCESS_JTAC:New( self, TaskUnit, self.TargetSetUnit, self.FACUnit ) ) - A2GUnitProcess:AddTransition( "Accounted", "Success", "Success" ) - A2GUnitProcess:AddTransition( "Failed", "Fail", "Failed" ) - - function A2GUnitProcess:onenterUpdated( TaskUnit ) - self:E( { self } ) - self:Account() - self:Smoke() - end - - - - --_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self ) - --_EVENTDISPATCHER:OnDead( self._EventDead, self ) - --_EVENTDISPATCHER:OnCrash( self._EventDead, self ) - --_EVENTDISPATCHER:OnPilotDead( self._EventDead, self ) - - return self - end - - --- @param #TASK_A2G self - function TASK_A2G:GetPlannedMenuText() - return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" - end - - end - - - ---- The main include file for the MOOSE system. - ---- Core Routines -Include.File( "Utilities/Routines" ) -Include.File( "Utilities/Utils" ) - ---- Core Classes -Include.File( "Core/Base" ) -Include.File( "Core/Scheduler" ) -Include.File( "Core/ScheduleDispatcher") -Include.File( "Core/Event" ) -Include.File( "Core/Menu" ) -Include.File( "Core/Zone" ) -Include.File( "Core/Database" ) -Include.File( "Core/Set" ) -Include.File( "Core/Point" ) -Include.File( "Core/Message" ) -Include.File( "Core/Fsm" ) - ---- Wrapper Classes -Include.File( "Wrapper/Object" ) -Include.File( "Wrapper/Identifiable" ) -Include.File( "Wrapper/Positionable" ) -Include.File( "Wrapper/Controllable" ) -Include.File( "Wrapper/Group" ) -Include.File( "Wrapper/Unit" ) -Include.File( "Wrapper/Client" ) -Include.File( "Wrapper/Static" ) -Include.File( "Wrapper/Airbase" ) - ---- Functional Classes -Include.File( "Functional/Scoring" ) -Include.File( "Functional/CleanUp" ) -Include.File( "Functional/Spawn" ) -Include.File( "Functional/Movement" ) -Include.File( "Functional/Sead" ) -Include.File( "Functional/Escort" ) -Include.File( "Functional/MissileTrainer" ) -Include.File( "Functional/AirbasePolice" ) -Include.File( "Functional/Detection" ) - ---- AI Classes -Include.File( "AI/AI_Balancer" ) -Include.File( "AI/AI_Patrol" ) -Include.File( "AI/AI_Cargo" ) -Include.File( "AI/AI_Cas" ) - ---- Actions -Include.File( "Actions/Act_Assign" ) -Include.File( "Actions/Act_Route" ) -Include.File( "Actions/Act_Account" ) -Include.File( "Actions/Act_Assist" ) - ---- Task Handling Classes -Include.File( "Tasking/CommandCenter" ) -Include.File( "Tasking/Mission" ) -Include.File( "Tasking/Task" ) -Include.File( "Tasking/DetectionManager" ) -Include.File( "Tasking/Task_SEAD" ) -Include.File( "Tasking/Task_A2G" ) - - --- The order of the declarations is important here. Don't touch it. - ---- Declare the event dispatcher based on the EVENT class -_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT - ---- Declare the timer dispatcher based on the SCHEDULEDISPATCHER class -_SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER - ---- Declare the main database object, which is used internally by the MOOSE classes. -_DATABASE = DATABASE:New() -- Database#DATABASE +Include.ProgramPath = "Scripts/Moose/" +env.info( "Include.ProgramPath = " .. Include.ProgramPath) +Include.Files = {} +Include.File( "Moose" ) -BASE:TraceOnOff( false ) +BASE:TraceOnOff( true ) env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 1e630b10b..57003e86e 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,30588 +1,31 @@ -env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170113_2007' ) +env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) +env.info( 'Moose Generation Timestamp: 20170113_2015' ) + local base = _G Include = {} -Include.Files = {} + Include.File = function( IncludeFile ) -end - ---- Various routines --- @module routines --- @author Flightcontrol - -env.setErrorMessageBoxEnabled(false) - ---- Extract of MIST functions. --- @author Grimes - -routines = {} - - --- don't change these -routines.majorVersion = 3 -routines.minorVersion = 3 -routines.build = 22 - ------------------------------------------------------------------------------------------------------------------ - ----------------------------------------------------------------------------------------------- --- Utils- conversion, Lua utils, etc. -routines.utils = {} - ---from http://lua-users.org/wiki/CopyTable -routines.utils.deepCopy = function(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - local objectreturn = _copy(object) - return objectreturn -end - - --- porting in Slmod's serialize_slmod2 -routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - - lookup_table = {} - - local function _Serialize( tbl ) - - if type(tbl) == 'table' then --function only works for tables! - - if lookup_table[tbl] then - return lookup_table[object] - end - - local tbl_str = {} - - lookup_table[tbl] = tbl_str - - tbl_str[#tbl_str + 1] = '{' - - for ind,val in pairs(tbl) do -- serialize its fields - local ind_str = {} - if type(ind) == "number" then - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = tostring(ind) - ind_str[#ind_str + 1] = ']=' - else --must be a string - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) - ind_str[#ind_str + 1] = ']=' - end - - local val_str = {} - if ((type(val) == 'number') or (type(val) == 'boolean')) then - val_str[#val_str + 1] = tostring(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'string' then - val_str[#val_str + 1] = routines.utils.basicSerialize(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'nil' then -- won't ever happen, right? - val_str[#val_str + 1] = 'nil,' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'table' then - if ind == "__index" then - -- tbl_str[#tbl_str + 1] = "__index" - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - - val_str[#val_str + 1] = _Serialize(val) - val_str[#val_str + 1] = ',' --I think this is right, I just added it - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - end - elseif type(val) == 'function' then - -- tbl_str[#tbl_str + 1] = "function " .. tostring(ind) - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else --- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) --- env.info( debug.traceback() ) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) + if not Include.Files[ IncludeFile ] then + Include.Files[IncludeFile] = IncludeFile + env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath ) + local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) ) + if f == nil then + error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) else - return tostring(tbl) + env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) + return f() end end - - local objectreturn = _Serialize(tbl) - return objectreturn end ---porting in Slmod's "safestring" basic serialize -routines.utils.basicSerialize = function(s) - if s == nil then - return "\"\"" - else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) - return s - end - end -end - - -routines.utils.toDegree = function(angle) - return angle*180/math.pi -end - -routines.utils.toRadian = function(angle) - return angle*math.pi/180 -end - -routines.utils.metersToNM = function(meters) - return meters/1852 -end - -routines.utils.metersToFeet = function(meters) - return meters/0.3048 -end - -routines.utils.NMToMeters = function(NM) - return NM*1852 -end - -routines.utils.feetToMeters = function(feet) - return feet*0.3048 -end - -routines.utils.mpsToKnots = function(mps) - return mps*3600/1852 -end - -routines.utils.mpsToKmph = function(mps) - return mps*3.6 -end - -routines.utils.knotsToMps = function(knots) - return knots*1852/3600 -end - -routines.utils.kmphToMps = function(kmph) - return kmph/3.6 -end - -function routines.utils.makeVec2(Vec3) - if Vec3.z then - return {x = Vec3.x, y = Vec3.z} - else - return {x = Vec3.x, y = Vec3.y} -- it was actually already vec2. - end -end - -function routines.utils.makeVec3(Vec2, y) - if not Vec2.z then - if not y then - y = 0 - end - return {x = Vec2.x, y = y, z = Vec2.y} - else - return {x = Vec2.x, y = Vec2.y, z = Vec2.z} -- it was already Vec3, actually. - end -end - -function routines.utils.makeVec3GL(Vec2, offset) - local adj = offset or 0 - - if not Vec2.z then - return {x = Vec2.x, y = (land.getHeight(Vec2) + adj), z = Vec2.y} - else - return {x = Vec2.x, y = (land.getHeight({x = Vec2.x, y = Vec2.z}) + adj), z = Vec2.z} - end -end - -routines.utils.zoneToVec3 = function(zone) - local new = {} - if type(zone) == 'table' and zone.point then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - elseif type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - if zone then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - return new - end - end -end - --- gets heading-error corrected direction from point along vector vec. -function routines.utils.getDir(vec, point) - local dir = math.atan2(vec.z, vec.x) - dir = dir + routines.getNorthCorrection(point) - if dir < 0 then - dir = dir + 2*math.pi -- put dir in range of 0 to 2*pi - end - return dir -end - --- gets distance in meters between two points (2 dimensional) -function routines.utils.get2DDist(point1, point2) - point1 = routines.utils.makeVec3(point1) - point2 = routines.utils.makeVec3(point2) - return routines.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) -end - --- gets distance in meters between two points (3 dimensional) -function routines.utils.get3DDist(point1, point2) - return routines.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) -end - - - - - ---3D Vector manipulation -routines.vec = {} - -routines.vec.add = function(vec1, vec2) - return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} -end - -routines.vec.sub = function(vec1, vec2) - return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} -end - -routines.vec.scalarMult = function(vec, mult) - return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} -end - -routines.vec.scalar_mult = routines.vec.scalarMult - -routines.vec.dp = function(vec1, vec2) - return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z -end - -routines.vec.cp = function(vec1, vec2) - return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} -end - -routines.vec.mag = function(vec) - return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 -end - -routines.vec.getUnitVec = function(vec) - local mag = routines.vec.mag(vec) - return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } -end - -routines.vec.rotateVec2 = function(vec2, theta) - return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} -end ---------------------------------------------------------------------------------------------------------------------------- - - - - --- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -routines.tostringMGRS = function(MGRS, acc) - if acc == 0 then - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph - else - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Easting/(10^(5-acc)), 0)) - .. ' ' .. string.format('%0' .. acc .. 'd', routines.utils.round(MGRS.Northing/(10^(5-acc)), 0)) - end -end - ---[[acc: -in DM: decimal point of minutes. -In DMS: decimal point of seconds. -position after the decimal of the least significant digit: -So: -42.32 - acc of 2. -]] -routines.tostringLL = function(lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = routines.utils.round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = routines.utils.round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - - else -- degrees, decimal minutes. - latMin = routines.utils.round(latMin, acc) - lonMin = routines.utils.round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end -end - ---[[ required: az - radian - required: dist - meters - optional: alt - meters (set to false or nil if you don't want to use it). - optional: metric - set true to get dist and alt in km and m. - precision will always be nearest degree and NM or km.]] -routines.tostringBR = function(az, dist, alt, metric) - az = routines.utils.round(routines.utils.toDegree(az), 0) - - if metric then - dist = routines.utils.round(dist/1000, 2) - else - dist = routines.utils.round(routines.utils.metersToNM(dist), 2) - end - - local s = string.format('%03d', az) .. ' for ' .. dist - - if alt then - if metric then - s = s .. ' at ' .. routines.utils.round(alt, 0) - else - s = s .. ' at ' .. routines.utils.round(routines.utils.metersToFeet(alt), 0) - end - end - return s -end - -routines.getNorthCorrection = function(point) --gets the correction needed for true north - if not point.z then --Vec2; convert to Vec3 - point.z = point.y - point.y = 0 - end - local lat, lon = coord.LOtoLL(point) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2(north_posit.z - point.z, north_posit.x - point.x) -end - - -do - local idNum = 0 - - --Simplified event handler - routines.addEventHandler = function(f) --id is optional! - local handler = {} - idNum = idNum + 1 - handler.id = idNum - handler.f = f - handler.onEvent = function(self, event) - self.f(event) - end - world.addEventHandler(handler) - end - - routines.removeEventHandler = function(id) - for key, handler in pairs(world.eventHandlers) do - if handler.id and handler.id == id then - world.eventHandlers[key] = nil - return true - end - end - return false - end -end - --- need to return a Vec3 or Vec2? -function routines.getRandPointInCircle(point, radius, innerRadius) - local theta = 2*math.pi*math.random() - local rad = math.random() + math.random() - if rad > 1 then - rad = 2 - rad - end - - local radMult - if innerRadius and innerRadius <= radius then - radMult = (radius - innerRadius)*rad + innerRadius - else - radMult = radius*rad - end - - if not point.z then --might as well work with vec2/3 - point.z = point.y - end - - local rndCoord - if radius > 0 then - rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} - else - rndCoord = {x = point.x, y = point.z} - end - return rndCoord -end - -routines.goRoute = function(group, path) - local misTask = { - id = 'Mission', - params = { - route = { - points = routines.utils.deepCopy(path), - }, - }, - } - if type(group) == 'string' then - group = Group.getByName(group) - end - local groupCon = group:getController() - if groupCon then - groupCon:setTask(misTask) - return true - end - - Controller.setTask(groupCon, misTask) - return false -end - - --- Useful atomic functions from mist, ported. - -routines.ground = {} -routines.fixedWing = {} -routines.heli = {} - -routines.ground.buildWP = function(point, overRideForm, overRideSpeed) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - local form, speed - - if point.speed and not overRideSpeed then - wp.speed = point.speed - elseif type(overRideSpeed) == 'number' then - wp.speed = overRideSpeed - else - wp.speed = routines.utils.kmphToMps(20) - end - - if point.form and not overRideForm then - form = point.form - else - form = overRideForm - end - - if not form then - wp.action = 'Cone' - else - form = string.lower(form) - if form == 'off_road' or form == 'off road' then - wp.action = 'Off Road' - elseif form == 'on_road' or form == 'on road' then - wp.action = 'On Road' - elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then - wp.action = 'Rank' - elseif form == 'cone' then - wp.action = 'Cone' - elseif form == 'diamond' then - wp.action = 'Diamond' - elseif form == 'vee' then - wp.action = 'Vee' - elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then - wp.action = 'EchelonL' - elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then - wp.action = 'EchelonR' - else - wp.action = 'Cone' -- if nothing matched - end - end - - wp.type = 'Turning Point' - - return wp - -end - -routines.fixedWing.buildWP = function(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 2000 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = routines.utils.kmphToMps(500) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp -end - -routines.heli.buildWP = function(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 500 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = routines.utils.kmphToMps(200) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp -end - -routines.groupToRandomPoint = function(vars) - local group = vars.group --Required - local point = vars.point --required - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - local form = vars.form or 'Cone' - local heading = vars.heading or math.random()*2*math.pi - local headingDegrees = vars.headingDegrees - local speed = vars.speed or routines.utils.kmphToMps(20) - - - local useRoads - if not vars.disableRoads then - useRoads = true - else - useRoads = false - end - - local path = {} - - if headingDegrees then - heading = headingDegrees*math.pi/180 - end - - if heading >= 2*math.pi then - heading = heading - 2*math.pi - end - - local rndCoord = routines.getRandPointInCircle(point, radius, innerRadius) - - local offset = {} - local posStart = routines.getLeadPos(group) - - offset.x = routines.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) - offset.z = routines.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) - path[#path + 1] = routines.ground.buildWP(posStart, form, speed) - - - if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then - path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed) - path[#path + 1] = routines.ground.buildWP(posStart, 'on_road', speed) - path[#path + 1] = routines.ground.buildWP(offset, 'on_road', speed) - else - path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed) - end - - path[#path + 1] = routines.ground.buildWP(offset, form, speed) - path[#path + 1] = routines.ground.buildWP(rndCoord, form, speed) - - routines.goRoute(group, path) - - return -end - -routines.groupRandomDistSelf = function(gpData, dist, form, heading, speed) - local pos = routines.getLeadPos(gpData) - local fakeZone = {} - fakeZone.radius = dist or math.random(300, 1000) - fakeZone.point = {x = pos.x, y, pos.y, z = pos.z} - routines.groupToRandomZone(gpData, fakeZone, form, heading, speed) - - return -end - -routines.groupToRandomZone = function(gpData, zone, form, heading, speed) - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - if type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - elseif type(zone) == 'table' and not zone.radius then - zone = trigger.misc.getZone(zone[math.random(1, #zone)]) - end - - if speed then - speed = routines.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.radius = zone.radius - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.point = routines.utils.zoneToVec3(zone) - - routines.groupToRandomPoint(vars) - - return -end - -routines.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types - if coord.z then - coord.y = coord.z - end - local typeConverted = {} - - if type(terrainTypes) == 'string' then -- if its a string it does this check - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then - table.insert(typeConverted, constId) - end - end - elseif type(terrainTypes) == 'table' then -- if its a table it does this check - for typeId, typeData in pairs(terrainTypes) do - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then - table.insert(typeConverted, constId) - end - end - end - end - for validIndex, validData in pairs(typeConverted) do - if land.getSurfaceType(coord) == land.SurfaceType[validData] then - return true - end - end - return false -end - -routines.groupToPoint = function(gpData, point, form, heading, speed, useRoads) - if type(point) == 'string' then - point = trigger.misc.getZone(point) - end - if speed then - speed = routines.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.disableRoads = useRoads - vars.point = routines.utils.zoneToVec3(point) - routines.groupToRandomPoint(vars) - - return -end - - -routines.getLeadPos = function(group) - if type(group) == 'string' then -- group name - group = Group.getByName(group) - end - - local units = group:getUnits() - - local leader = units[1] - if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then. - local lowestInd = math.huge - for ind, unit in pairs(units) do - if ind < lowestInd then - lowestInd = ind - leader = unit - end - end - end - if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... - return leader:getPosition().p - end -end - ---[[ vars for routines.getMGRSString: -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -]] -routines.getMGRSString = function(vars) - local units = vars.units - local acc = vars.acc or 5 - local avgPos = routines.getAvgPos(units) - if avgPos then - return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) - end -end - ---[[ vars for routines.getLLString -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. - - -]] -routines.getLLString = function(vars) - local units = vars.units - local acc = vars.acc or 3 - local DMS = vars.DMS - local avgPos = routines.getAvgPos(units) - if avgPos then - local lat, lon = coord.LOtoLL(avgPos) - return routines.tostringLL(lat, lon, acc, DMS) - end -end - ---[[ -vars.zone - table of a zone name. -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -]] -routines.getBRStringZone = function(vars) - local zone = trigger.misc.getZone( vars.zone ) - local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - if zone then - local vec = {x = zone.point.x - ref.x, y = zone.point.y - ref.y, z = zone.point.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(zone.point, ref) - if alt then - alt = zone.y - end - return routines.tostringBR(dir, dist, alt, metric) - else - env.info( 'routines.getBRStringZone: error: zone is nil' ) - end -end - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -]] -routines.getBRString = function(vars) - local units = vars.units - local ref = routines.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - local avgPos = routines.getAvgPos(units) - if avgPos then - local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(avgPos, ref) - if alt then - alt = avgPos.y - end - return routines.tostringBR(dir, dist, alt, metric) - end -end - - --- Returns the Vec3 coordinates of the average position of the concentration of units most in the heading direction. ---[[ vars for routines.getLeadingPos: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -]] -routines.getLeadingPos = function(vars) - local units = vars.units - local heading = vars.heading - local radius = vars.radius - if vars.headingDegrees then - heading = routines.utils.toRadian(vars.headingDegrees) - end - - local unitPosTbl = {} - for i = 1, #units do - local unit = Unit.getByName(units[i]) - if unit and unit:isExist() then - unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p - end - end - if #unitPosTbl > 0 then -- one more more units found. - -- first, find the unit most in the heading direction - local maxPos = -math.huge - - local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = - for i = 1, #unitPosTbl do - local rotatedVec2 = routines.vec.rotateVec2(routines.utils.makeVec2(unitPosTbl[i]), heading) - if (not maxPos) or maxPos < rotatedVec2.x then - maxPos = rotatedVec2.x - maxPosInd = i - end - end - - --now, get all the units around this unit... - local avgPos - if radius then - local maxUnitPos = unitPosTbl[maxPosInd] - local avgx, avgy, avgz, totNum = 0, 0, 0, 0 - for i = 1, #unitPosTbl do - if routines.utils.get2DDist(maxUnitPos, unitPosTbl[i]) <= radius then - avgx = avgx + unitPosTbl[i].x - avgy = avgy + unitPosTbl[i].y - avgz = avgz + unitPosTbl[i].z - totNum = totNum + 1 - end - end - avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} - else - avgPos = unitPosTbl[maxPosInd] - end - - return avgPos - end -end - - ---[[ vars for routines.getLeadingMGRSString: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number, 0 to 5. -]] -routines.getLeadingMGRSString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local acc = vars.acc or 5 - return routines.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) - end -end - ---[[ vars for routines.getLeadingLLString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. -]] -routines.getLeadingLLString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local acc = vars.acc or 3 - local DMS = vars.DMS - local lat, lon = coord.LOtoLL(pos) - return routines.tostringLL(lat, lon, acc, DMS) - end -end - - - ---[[ vars for routines.getLeadingBRString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.metric - boolean, if true, use km instead of NM. -vars.alt - boolean, if true, include altitude. -vars.ref - vec3/vec2 reference point. -]] -routines.getLeadingBRString = function(vars) - local pos = routines.getLeadingPos(vars) - if pos then - local ref = vars.ref - local alt = vars.alt - local metric = vars.metric - - local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} - local dir = routines.utils.getDir(vec, ref) - local dist = routines.utils.get2DDist(pos, ref) - if alt then - alt = pos.y - end - return routines.tostringBR(dir, dist, alt, metric) - end -end - ---[[ vars for routines.message.add - vars.text = 'Hello World' - vars.displayTime = 20 - vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} - -]] - ---[[ vars for routines.msgMGRS -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] -routines.msgMGRS = function(vars) - local units = vars.units - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getMGRSString{units = units, acc = acc} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } -end - ---[[ vars for routines.msgLL -vars.units - table of unit names (NOT unitNameTable- maybe this should change) (Yes). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] -routines.msgLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLLString{units = units, acc = acc, DMS = DMS} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString - local alt = vars.alt - local metric = vars.metric - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getBRString{units = units, ref = ref, alt = alt, metric = metric} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - - --------------------------------------------------------------------------------------------- --- basically, just sub-types of routines.msgBR... saves folks the work of getting the ref point. ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - string red, blue -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgBullseye = function(vars) - if string.lower(vars.ref) == 'red' then - vars.ref = routines.DBs.missionData.bullseye.red - routines.msgBR(vars) - elseif string.lower(vars.ref) == 'blue' then - vars.ref = routines.DBs.missionData.bullseye.blue - routines.msgBR(vars) - end -end - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - unit name of reference point -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - -routines.msgBRA = function(vars) - if Unit.getByName(vars.ref) then - vars.ref = Unit.getByName(vars.ref):getPosition().p - if not vars.alt then - vars.alt = true - end - routines.msgBR(vars) - end -end --------------------------------------------------------------------------------------------- - ---[[ vars for routines.msgLeadingMGRS: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number, 0 to 5. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingMGRS = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - -end ---[[ vars for routines.msgLeadingLL: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. (optional) -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingLL = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - -end - ---[[ -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.metric - boolean, if true, use km instead of NM. (optional) -vars.alt - boolean, if true, include altitude. (optional) -vars.ref - vec3/vec2 reference point. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] -routines.msgLeadingBR = function(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local metric = vars.metric - local alt = vars.alt - local ref = vars.ref -- vec2/vec3 will be handled in routines.getBRString - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = routines.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} - local newText - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else -- else, just append to the end. - newText = text .. s - end - - routines.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } -end - - -function spairs(t, order) - -- collect the keys - local keys = {} - for k in pairs(t) do keys[#keys+1] = k end - - -- if order function given, sort by it by passing the table and keys a, b, - -- otherwise just sort the keys - if order then - table.sort(keys, function(a,b) return order(t, a, b) end) - else - table.sort(keys) - end - - -- return the iterator function - local i = 0 - return function() - i = i + 1 - if keys[i] then - return keys[i], t[keys[i]] - end - end -end - - -function routines.IsPartOfGroupInZones( CargoGroup, LandingZones ) ---trace.f() - - local CurrentZoneID = nil - - if CargoGroup then - local CargoUnits = CargoGroup:getUnits() - for CargoUnitID, CargoUnit in pairs( CargoUnits ) do - if CargoUnit and CargoUnit:getLife() >= 1.0 then - CurrentZoneID = routines.IsUnitInZones( CargoUnit, LandingZones ) - if CurrentZoneID then - break - end - end - end - end - ---trace.r( "", "", { CurrentZoneID } ) - return CurrentZoneID -end - - - -function routines.IsUnitInZones( TransportUnit, LandingZones ) ---trace.f("", "routines.IsUnitInZones" ) - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - if TransportUnit then - local TransportUnitPos = TransportUnit:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = 1 - end - end - if TransportZoneResult then - --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) - else - --trace.i( "routines", "TransportZone:nil logic" ) - end - return TransportZoneResult - else - --trace.i( "routines", "TransportZone:nil hard" ) - return nil - end -end - -function routines.IsUnitNearZonesRadius( TransportUnit, LandingZones, ZoneRadius ) ---trace.f("", "routines.IsUnitInZones" ) - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - if TransportUnit then - local TransportUnitPos = TransportUnit:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportUnitPos.x - TransportZonePos.x)^2 + (TransportUnitPos.z - TransportZonePos.z)^2)^0.5 <= ZoneRadius ) then - TransportZoneResult = 1 - end - end - if TransportZoneResult then - --trace.i( "routines", "TransportZone:" .. TransportZoneResult ) - else - --trace.i( "routines", "TransportZone:nil logic" ) - end - return TransportZoneResult - else - --trace.i( "routines", "TransportZone:nil hard" ) - return nil - end -end - - -function routines.IsStaticInZones( TransportStatic, LandingZones ) ---trace.f() - - local TransportZoneResult = nil - local TransportZonePos = nil - local TransportZone = nil - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - local TransportStaticPos = TransportStatic:getPosition().p - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - TransportZone = trigger.misc.getZone( LandingZoneName ) - if TransportZone then - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = LandingZoneID - break - end - end - end - else - TransportZone = trigger.misc.getZone( LandingZones ) - TransportZonePos = {radius = TransportZone.radius, x = TransportZone.point.x, y = TransportZone.point.y, z = TransportZone.point.z} - if ((( TransportStaticPos.x - TransportZonePos.x)^2 + (TransportStaticPos.z - TransportZonePos.z)^2)^0.5 <= TransportZonePos.radius) then - TransportZoneResult = 1 - end - end - ---trace.r( "", "", { TransportZoneResult } ) - return TransportZoneResult -end - - -function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius ) ---trace.f() - - local Valid = true - - -- fill-up some local variables to support further calculations to determine location of units within the zone. - local CargoPos = CargoUnit:getPosition().p - local ReferenceP = ReferencePosition.p - - if (((CargoPos.x - ReferenceP.x)^2 + (CargoPos.z - ReferenceP.z)^2)^0.5 <= Radius) then - else - Valid = false - end - - return Valid -end - -function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius ) ---trace.f() - - local Valid = true - - Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid ) - - -- fill-up some local variables to support further calculations to determine location of units within the zone - local CargoUnits = CargoGroup:getUnits() - for CargoUnitId, CargoUnit in pairs( CargoUnits ) do - local CargoUnitPos = CargoUnit:getPosition().p --- env.info( 'routines.IsPartOfGroupInRadius: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z ) - local ReferenceP = ReferencePosition.p --- env.info( 'routines.IsPartOfGroupInRadius: ReferenceGroupPos.x = ' .. ReferenceGroupPos.x .. ' ReferenceGroupPos.z = ' .. ReferenceGroupPos.z ) - - if ((( CargoUnitPos.x - ReferenceP.x)^2 + (CargoUnitPos.z - ReferenceP.z)^2)^0.5 <= Radius) then - else - Valid = false - break - end - end - - return Valid -end - - -function routines.ValidateString( Variable, VariableName, Valid ) ---trace.f() - - if type( Variable ) == "string" then - if Variable == "" then - error( "routines.ValidateString: error: " .. VariableName .. " must be filled out!" ) - Valid = false - end - else - error( "routines.ValidateString: error: " .. VariableName .. " is not a string." ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateNumber( Variable, VariableName, Valid ) ---trace.f() - - if type( Variable ) == "number" then - else - error( "routines.ValidateNumber: error: " .. VariableName .. " is not a number." ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid - -end - -function routines.ValidateGroup( Variable, VariableName, Valid ) ---trace.f() - - if Variable == nil then - error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateZone( LandingZones, VariableName, Valid ) ---trace.f() - - if LandingZones == nil then - error( "routines.ValidateGroup: error: " .. VariableName .. " is a nil value!" ) - Valid = false - end - - if type( LandingZones ) == "table" then - for LandingZoneID, LandingZoneName in pairs( LandingZones ) do - if trigger.misc.getZone( LandingZoneName ) == nil then - error( "routines.ValidateGroup: error: Zone " .. LandingZoneName .. " does not exist!" ) - Valid = false - break - end - end - else - if trigger.misc.getZone( LandingZones ) == nil then - error( "routines.ValidateGroup: error: Zone " .. LandingZones .. " does not exist!" ) - Valid = false - end - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.ValidateEnumeration( Variable, VariableName, Enum, Valid ) ---trace.f() - - local ValidVariable = false - - for EnumId, EnumData in pairs( Enum ) do - if Variable == EnumData then - ValidVariable = true - break - end - end - - if ValidVariable then - else - error( 'TransportValidateEnum: " .. VariableName .. " is not a valid type.' .. Variable ) - Valid = false - end - ---trace.r( "", "", { Valid } ) - return Valid -end - -function routines.getGroupRoute(groupIdent, task) -- same as getGroupPoints but returns speed and formation type along with vec2 of point} - -- refactor to search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - gpId = _DATABASE.Templates.Groups[groupIdent].groupId - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_type_name, obj_type_data in pairs(cntry_data) do - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" then -- only these types have points - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_type_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - - for point_num, point in pairs(group_data.route.points) do - local routeData = {} - if not point.point then - routeData.x = point.x - routeData.y = point.y - else - routeData.point = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - routeData.form = point.action - routeData.speed = point.speed - routeData.alt = point.alt - routeData.alt_type = point.alt_type - routeData.airdromeId = point.airdromeId - routeData.helipadId = point.helipadId - routeData.type = point.type - routeData.action = point.action - if task then - routeData.task = point.task - end - points[point_num] = routeData - end - - return points - end - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do -end - -routines.ground.patrolRoute = function(vars) - - - local tempRoute = {} - local useRoute = {} - local gpData = vars.gpData - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - local useGroupRoute - if not vars.useGroupRoute then - useGroupRoute = vars.gpData - else - useGroupRoute = vars.useGroupRoute - end - local routeProvided = false - if not vars.route then - if useGroupRoute then - tempRoute = routines.getGroupRoute(useGroupRoute) - end - else - useRoute = vars.route - local posStart = routines.getLeadPos(gpData) - useRoute[1] = routines.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) - routeProvided = true - end - - - local overRideSpeed = vars.speed or 'default' - local pType = vars.pType - local offRoadForm = vars.offRoadForm or 'default' - local onRoadForm = vars.onRoadForm or 'default' - - if routeProvided == false and #tempRoute > 0 then - local posStart = routines.getLeadPos(gpData) - - - useRoute[#useRoute + 1] = routines.ground.buildWP(posStart, offRoadForm, overRideSpeed) - for i = 1, #tempRoute do - local tempForm = tempRoute[i].action - local tempSpeed = tempRoute[i].speed - - if offRoadForm == 'default' then - tempForm = tempRoute[i].action - end - if onRoadForm == 'default' then - onRoadForm = 'On Road' - end - if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then - tempForm = onRoadForm - else - tempForm = offRoadForm - end - - if type(overRideSpeed) == 'number' then - tempSpeed = overRideSpeed - end - - - useRoute[#useRoute + 1] = routines.ground.buildWP(tempRoute[i], tempForm, tempSpeed) - end - - if pType and string.lower(pType) == 'doubleback' then - local curRoute = routines.utils.deepCopy(useRoute) - for i = #curRoute, 2, -1 do - useRoute[#useRoute + 1] = routines.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) - end - end - - useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP - end - - local cTask3 = {} - local newPatrol = {} - newPatrol.route = useRoute - newPatrol.gpData = gpData:getName() - cTask3[#cTask3 + 1] = 'routines.ground.patrolRoute(' - cTask3[#cTask3 + 1] = routines.utils.oneLineSerialize(newPatrol) - cTask3[#cTask3 + 1] = ')' - cTask3 = table.concat(cTask3) - local tempTask = { - id = 'WrappedAction', - params = { - action = { - id = 'Script', - params = { - command = cTask3, - - }, - }, - }, - } - - - useRoute[#useRoute].task = tempTask - routines.goRoute(gpData, useRoute) - - return -end - -routines.ground.patrol = function(gpData, pType, form, speed) - local vars = {} - - if type(gpData) == 'table' and gpData:getName() then - gpData = gpData:getName() - end - - vars.useGroupRoute = gpData - vars.gpData = gpData - vars.pType = pType - vars.offRoadForm = form - vars.speed = speed - - routines.ground.patrolRoute(vars) - - return -end - -function routines.GetUnitHeight( CheckUnit ) ---trace.f( "routines" ) - - local UnitPoint = CheckUnit:getPoint() - local UnitPosition = { x = UnitPoint.x, y = UnitPoint.z } - local UnitHeight = UnitPoint.y - - local LandHeight = land.getHeight( UnitPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - --trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight ) - - return UnitHeight - LandHeight - -end - - - -Su34Status = { status = {} } -boardMsgRed = { statusMsg = "" } -boardMsgAll = { timeMsg = "" } -SpawnSettings = {} -Su34MenuPath = {} -Su34Menus = 0 - - -function Su34AttackCarlVinson(groupName) ---trace.menu("", "Su34AttackCarlVinson") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupCarlVinson = Group.getByName("US Carl Vinson #001") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupCarlVinson ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupCarlVinson:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - Su34Status.status[groupName] = 1 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking carrier Carl Vinson. ', 10, 'RedStatus' .. groupName ) -end - -function Su34AttackWest(groupName) ---trace.f("","Su34AttackWest") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupShipWest1 = Group.getByName("US Ship West #001") - local groupShipWest2 = Group.getByName("US Ship West #002") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupShipWest1 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - if groupShipWest2 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipWest2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = true}}) - end - Su34Status.status[groupName] = 2 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the west. ', 10, 'RedStatus' .. groupName ) -end - -function Su34AttackNorth(groupName) ---trace.menu("","Su34AttackNorth") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34.getController(groupSu34) - local groupShipNorth1 = Group.getByName("US Ship North #001") - local groupShipNorth2 = Group.getByName("US Ship North #002") - local groupShipNorth3 = Group.getByName("US Ship North #003") - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - if groupShipNorth1 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth1:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - if groupShipNorth2 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth2:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - if groupShipNorth3 ~= nil then - controllerSu34.pushTask(controllerSu34,{id = 'AttackGroup', params = { groupId = groupShipNorth3:getID(), expend = AI.Task.WeaponExpend.ALL, attackQtyLimit = false}}) - end - Su34Status.status[groupName] = 3 - MessageToRed( string.format('%s: ',groupName) .. 'Attacking invading ships in the north. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Orbit(groupName) ---trace.menu("","Su34Orbit") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - controllerSu34:pushTask( {id = 'ControlledTask', params = { task = { id = 'Orbit', params = { pattern = AI.Task.OrbitPattern.RACE_TRACK } }, stopCondition = { duration = 600 } } } ) - Su34Status.status[groupName] = 4 - MessageToRed( string.format('%s: ',groupName) .. 'In orbit and awaiting further instructions. ', 10, 'RedStatus' .. groupName ) -end - -function Su34TakeOff(groupName) ---trace.menu("","Su34TakeOff") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - Su34Status.status[groupName] = 8 - MessageToRed( string.format('%s: ',groupName) .. 'Take-Off. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Hold(groupName) ---trace.menu("","Su34Hold") - local groupSu34 = Group.getByName( groupName ) - local controllerSu34 = groupSu34:getController() - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - controllerSu34.setOption( controllerSu34, AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - Su34Status.status[groupName] = 5 - MessageToRed( string.format('%s: ',groupName) .. 'Holding Weapons. ', 10, 'RedStatus' .. groupName ) -end - -function Su34RTB(groupName) ---trace.menu("","Su34RTB") - Su34Status.status[groupName] = 6 - MessageToRed( string.format('%s: ',groupName) .. 'Return to Krasnodar. ', 10, 'RedStatus' .. groupName ) -end - -function Su34Destroyed(groupName) ---trace.menu("","Su34Destroyed") - Su34Status.status[groupName] = 7 - MessageToRed( string.format('%s: ',groupName) .. 'Destroyed. ', 30, 'RedStatus' .. groupName ) -end - -function GroupAlive( groupName ) ---trace.menu("","GroupAlive") - local groupTest = Group.getByName( groupName ) - - local groupExists = false - - if groupTest then - groupExists = groupTest:isExist() - end - - --trace.r( "", "", { groupExists } ) - return groupExists -end - -function Su34IsDead() ---trace.f() - -end - -function Su34OverviewStatus() ---trace.menu("","Su34OverviewStatus") - local msg = "" - local currentStatus = 0 - local Exists = false - - for groupName, currentStatus in pairs(Su34Status.status) do - - env.info(('Su34 Overview Status: GroupName = ' .. groupName )) - Alive = GroupAlive( groupName ) - - if Alive then - if currentStatus == 1 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking carrier Carl Vinson. " - elseif currentStatus == 2 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking supporting ships in the west. " - elseif currentStatus == 3 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Attacking invading ships in the north. " - elseif currentStatus == 4 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "In orbit and awaiting further instructions. " - elseif currentStatus == 5 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Holding Weapons. " - elseif currentStatus == 6 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Return to Krasnodar. " - elseif currentStatus == 7 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Destroyed. " - elseif currentStatus == 8 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Take-Off. " - end - else - if currentStatus == 7 then - msg = msg .. string.format("%s: ",groupName) - msg = msg .. "Destroyed. " - else - Su34Destroyed(groupName) - end - end - end - - boardMsgRed.statusMsg = msg -end - - -function UpdateBoardMsg() ---trace.f() - Su34OverviewStatus() - MessageToRed( boardMsgRed.statusMsg, 15, 'RedStatus' ) -end - -function MusicReset( flg ) ---trace.f() - trigger.action.setUserFlag(95,flg) -end - -function PlaneActivate(groupNameFormat, flg) ---trace.f() - local groupName = groupNameFormat .. string.format("#%03d", trigger.misc.getUserFlag(flg)) - --trigger.action.outText(groupName,10) - trigger.action.activateGroup(Group.getByName(groupName)) -end - -function Su34Menu(groupName) ---trace.f() - - --env.info(( 'Su34Menu(' .. groupName .. ')' )) - local groupSu34 = Group.getByName( groupName ) - - if Su34Status.status[groupName] == 1 or - Su34Status.status[groupName] == 2 or - Su34Status.status[groupName] == 3 or - Su34Status.status[groupName] == 4 or - Su34Status.status[groupName] == 5 then - if Su34MenuPath[groupName] == nil then - if planeMenuPath == nil then - planeMenuPath = missionCommands.addSubMenuForCoalition( - coalition.side.RED, - "SU-34 anti-ship flights", - nil - ) - end - Su34MenuPath[groupName] = missionCommands.addSubMenuForCoalition( - coalition.side.RED, - "Flight " .. groupName, - planeMenuPath - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack carrier Carl Vinson", - Su34MenuPath[groupName], - Su34AttackCarlVinson, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack ships in the west", - Su34MenuPath[groupName], - Su34AttackWest, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Attack ships in the north", - Su34MenuPath[groupName], - Su34AttackNorth, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Hold position and await instructions", - Su34MenuPath[groupName], - Su34Orbit, - groupName - ) - - missionCommands.addCommandForCoalition( - coalition.side.RED, - "Report status", - Su34MenuPath[groupName], - Su34OverviewStatus - ) - end - else - if Su34MenuPath[groupName] then - missionCommands.removeItemForCoalition(coalition.side.RED, Su34MenuPath[groupName]) - end - end -end - ---- Obsolete function, but kept to rework in framework. - -function ChooseInfantry ( TeleportPrefixTable, TeleportMax ) ---trace.f("Spawn") - --env.info(( 'ChooseInfantry: ' )) - - TeleportPrefixTableCount = #TeleportPrefixTable - TeleportPrefixTableIndex = math.random( 1, TeleportPrefixTableCount ) - - --env.info(( 'ChooseInfantry: TeleportPrefixTableIndex = ' .. TeleportPrefixTableIndex .. ' TeleportPrefixTableCount = ' .. TeleportPrefixTableCount .. ' TeleportMax = ' .. TeleportMax )) - - local TeleportFound = false - local TeleportLoop = true - local Index = TeleportPrefixTableIndex - local TeleportPrefix = '' - - while TeleportLoop do - TeleportPrefix = TeleportPrefixTable[Index] - if SpawnSettings[TeleportPrefix] then - if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then - SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 - TeleportFound = true - else - TeleportFound = false - end - else - SpawnSettings[TeleportPrefix] = {} - SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 - TeleportFound = true - end - if TeleportFound then - TeleportLoop = false - else - if Index < TeleportPrefixTableCount then - Index = Index + 1 - else - TeleportLoop = false - end - end - --env.info(( 'ChooseInfantry: Loop 1 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) - end - - if TeleportFound == false then - TeleportLoop = true - Index = 1 - while TeleportLoop do - TeleportPrefix = TeleportPrefixTable[Index] - if SpawnSettings[TeleportPrefix] then - if SpawnSettings[TeleportPrefix]['SpawnCount'] - 1 < TeleportMax then - SpawnSettings[TeleportPrefix]['SpawnCount'] = SpawnSettings[TeleportPrefix]['SpawnCount'] + 1 - TeleportFound = true - else - TeleportFound = false - end - else - SpawnSettings[TeleportPrefix] = {} - SpawnSettings[TeleportPrefix]['SpawnCount'] = 0 - TeleportFound = true - end - if TeleportFound then - TeleportLoop = false - else - if Index < TeleportPrefixTableIndex then - Index = Index + 1 - else - TeleportLoop = false - end - end - --env.info(( 'ChooseInfantry: Loop 2 - TeleportPrefix = ' .. TeleportPrefix .. ' Index = ' .. Index )) - end - end - - local TeleportGroupName = '' - if TeleportFound == true then - TeleportGroupName = TeleportPrefix .. string.format("#%03d", SpawnSettings[TeleportPrefix]['SpawnCount'] ) - else - TeleportGroupName = '' - end - - --env.info(('ChooseInfantry: TeleportGroupName = ' .. TeleportGroupName )) - --env.info(('ChooseInfantry: return')) - - return TeleportGroupName -end - -SpawnedInfantry = 0 - -function LandCarrier ( CarrierGroup, LandingZonePrefix ) ---trace.f() - --env.info(( 'LandCarrier: ' )) - --env.info(( 'LandCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) - --env.info(( 'LandCarrier: LandingZone = ' .. LandingZonePrefix )) - - local controllerGroup = CarrierGroup:getController() - - local LandingZone = trigger.misc.getZone(LandingZonePrefix) - local LandingZonePos = {} - LandingZonePos.x = LandingZone.point.x + math.random(LandingZone.radius * -1, LandingZone.radius) - LandingZonePos.y = LandingZone.point.z + math.random(LandingZone.radius * -1, LandingZone.radius) - - controllerGroup:pushTask( { id = 'Land', params = { point = LandingZonePos, durationFlag = true, duration = 10 } } ) - - --env.info(( 'LandCarrier: end' )) -end - -EscortCount = 0 -function EscortCarrier ( CarrierGroup, EscortPrefix, EscortLastWayPoint, EscortEngagementDistanceMax, EscortTargetTypes ) ---trace.f() - --env.info(( 'EscortCarrier: ' )) - --env.info(( 'EscortCarrier: CarrierGroup = ' .. CarrierGroup:getName() )) - --env.info(( 'EscortCarrier: EscortPrefix = ' .. EscortPrefix )) - - local CarrierName = CarrierGroup:getName() - - local EscortMission = {} - local CarrierMission = {} - - local EscortMission = SpawnMissionGroup( EscortPrefix ) - local CarrierMission = SpawnMissionGroup( CarrierGroup:getName() ) - - if EscortMission ~= nil and CarrierMission ~= nil then - - EscortCount = EscortCount + 1 - EscortMissionName = string.format( EscortPrefix .. '#Escort %s', CarrierName ) - EscortMission.name = EscortMissionName - EscortMission.groupId = nil - EscortMission.lateActivation = false - EscortMission.taskSelected = false - - local EscortUnits = #EscortMission.units - for u = 1, EscortUnits do - EscortMission.units[u].name = string.format( EscortPrefix .. '#Escort %s %02d', CarrierName, u ) - EscortMission.units[u].unitId = nil - end - - - EscortMission.route.points[1].task = { id = "ComboTask", - params = - { - tasks = - { - [1] = - { - enabled = true, - auto = false, - id = "Escort", - number = 1, - params = - { - lastWptIndexFlagChangedManually = false, - groupId = CarrierGroup:getID(), - lastWptIndex = nil, - lastWptIndexFlag = false, - engagementDistMax = EscortEngagementDistanceMax, - targetTypes = EscortTargetTypes, - pos = - { - y = 20, - x = 20, - z = 0, - } -- end of ["pos"] - } -- end of ["params"] - } -- end of [1] - } -- end of ["tasks"] - } -- end of ["params"] - } -- end of ["task"] - - SpawnGroupAdd( EscortPrefix, EscortMission ) - - end -end - -function SendMessageToCarrier( CarrierGroup, CarrierMessage ) ---trace.f() - - if CarrierGroup ~= nil then - MessageToGroup( CarrierGroup, CarrierMessage, 30, 'Carrier/' .. CarrierGroup:getName() ) - end - -end - -function MessageToGroup( MsgGroup, MsgText, MsgTime, MsgName ) ---trace.f() - - if type(MsgGroup) == 'string' then - --env.info( 'MessageToGroup: Converted MsgGroup string "' .. MsgGroup .. '" into a Group structure.' ) - MsgGroup = Group.getByName( MsgGroup ) - end - - if MsgGroup ~= nil then - local MsgTable = {} - MsgTable.text = MsgText - MsgTable.displayTime = MsgTime - MsgTable.msgFor = { units = { MsgGroup:getUnits()[1]:getName() } } - MsgTable.name = MsgName - --routines.message.add( MsgTable ) - --env.info(('MessageToGroup: Message sent to ' .. MsgGroup:getUnits()[1]:getName() .. ' -> ' .. MsgText )) - end -end - -function MessageToUnit( UnitName, MsgText, MsgTime, MsgName ) ---trace.f() - - if UnitName ~= nil then - local MsgTable = {} - MsgTable.text = MsgText - MsgTable.displayTime = MsgTime - MsgTable.msgFor = { units = { UnitName } } - MsgTable.name = MsgName - --routines.message.add( MsgTable ) - end -end - -function MessageToAll( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "Message" ):ToCoalition( coalition.side.RED ):ToCoalition( coalition.side.BLUE ) -end - -function MessageToRed( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "To Red Coalition" ):ToCoalition( coalition.side.RED ) -end - -function MessageToBlue( MsgText, MsgTime, MsgName ) ---trace.f() - - MESSAGE:New( MsgText, MsgTime, "To Blue Coalition" ):ToCoalition( coalition.side.RED ) -end - -function getCarrierHeight( CarrierGroup ) ---trace.f() - - if CarrierGroup ~= nil then - if table.getn(CarrierGroup:getUnits()) == 1 then - local CarrierUnit = CarrierGroup:getUnits()[1] - local CurrentPoint = CarrierUnit:getPoint() - - local CurrentPosition = { x = CurrentPoint.x, y = CurrentPoint.z } - local CarrierHeight = CurrentPoint.y - - local LandHeight = land.getHeight( CurrentPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - return CarrierHeight - LandHeight - else - return 999999 - end - else - return 999999 - end - -end - -function GetUnitHeight( CheckUnit ) ---trace.f() - - local UnitPoint = CheckUnit:getPoint() - local UnitPosition = { x = CurrentPoint.x, y = CurrentPoint.z } - local UnitHeight = CurrentPoint.y - - local LandHeight = land.getHeight( CurrentPosition ) - - --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) - - return UnitHeight - LandHeight - -end - - -_MusicTable = {} -_MusicTable.Files = {} -_MusicTable.Queue = {} -_MusicTable.FileCnt = 0 - - -function MusicRegister( SndRef, SndFile, SndTime ) ---trace.f() - - env.info(( 'MusicRegister: SndRef = ' .. SndRef )) - env.info(( 'MusicRegister: SndFile = ' .. SndFile )) - env.info(( 'MusicRegister: SndTime = ' .. SndTime )) - - - _MusicTable.FileCnt = _MusicTable.FileCnt + 1 - - _MusicTable.Files[_MusicTable.FileCnt] = {} - _MusicTable.Files[_MusicTable.FileCnt].Ref = SndRef - _MusicTable.Files[_MusicTable.FileCnt].File = SndFile - _MusicTable.Files[_MusicTable.FileCnt].Time = SndTime - - if not _MusicTable.Function then - _MusicTable.Function = routines.scheduleFunction( MusicScheduler, { }, timer.getTime() + 10, 10) - end - -end - -function MusicToPlayer( SndRef, PlayerName, SndContinue ) ---trace.f() - - --env.info(( 'MusicToPlayer: SndRef = ' .. SndRef )) - - local PlayerUnits = AlivePlayerUnits() - for PlayerUnitIdx, PlayerUnit in pairs(PlayerUnits) do - local PlayerUnitName = PlayerUnit:getPlayerName() - --env.info(( 'MusicToPlayer: PlayerUnitName = ' .. PlayerUnitName )) - if PlayerName == PlayerUnitName then - PlayerGroup = PlayerUnit:getGroup() - if PlayerGroup then - --env.info(( 'MusicToPlayer: PlayerGroup = ' .. PlayerGroup:getName() )) - MusicToGroup( SndRef, PlayerGroup, SndContinue ) - end - break - end - end - - --env.info(( 'MusicToPlayer: end' )) - -end - -function MusicToGroup( SndRef, SndGroup, SndContinue ) ---trace.f() - - --env.info(( 'MusicToGroup: SndRef = ' .. SndRef )) - - if SndGroup ~= nil then - if _MusicTable and _MusicTable.FileCnt > 0 then - if SndGroup:isExist() then - if MusicCanStart(SndGroup:getUnit(1):getPlayerName()) then - --env.info(( 'MusicToGroup: OK for Sound.' )) - local SndIdx = 0 - if SndRef == '' then - --env.info(( 'MusicToGroup: SndRef as empty. Queueing at random.' )) - SndIdx = math.random( 1, _MusicTable.FileCnt ) - else - for SndIdx = 1, _MusicTable.FileCnt do - if _MusicTable.Files[SndIdx].Ref == SndRef then - break - end - end - end - --env.info(( 'MusicToGroup: SndIdx = ' .. SndIdx )) - --env.info(( 'MusicToGroup: Queueing Music ' .. _MusicTable.Files[SndIdx].File .. ' for Group ' .. SndGroup:getID() )) - trigger.action.outSoundForGroup( SndGroup:getID(), _MusicTable.Files[SndIdx].File ) - MessageToGroup( SndGroup, 'Playing ' .. _MusicTable.Files[SndIdx].File, 15, 'Music-' .. SndGroup:getUnit(1):getPlayerName() ) - - local SndQueueRef = SndGroup:getUnit(1):getPlayerName() - if _MusicTable.Queue[SndQueueRef] == nil then - _MusicTable.Queue[SndQueueRef] = {} - end - _MusicTable.Queue[SndQueueRef].Start = timer.getTime() - _MusicTable.Queue[SndQueueRef].PlayerName = SndGroup:getUnit(1):getPlayerName() - _MusicTable.Queue[SndQueueRef].Group = SndGroup - _MusicTable.Queue[SndQueueRef].ID = SndGroup:getID() - _MusicTable.Queue[SndQueueRef].Ref = SndIdx - _MusicTable.Queue[SndQueueRef].Continue = SndContinue - _MusicTable.Queue[SndQueueRef].Type = Group - end - end - end - end -end - -function MusicCanStart(PlayerName) ---trace.f() - - --env.info(( 'MusicCanStart:' )) - - local MusicOut = false - - if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then - --env.info(( 'MusicCanStart: PlayerName = ' .. PlayerName )) - local PlayerFound = false - local MusicStart = 0 - local MusicTime = 0 - for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do - if SndQueue.PlayerName == PlayerName then - PlayerFound = true - MusicStart = SndQueue.Start - MusicTime = _MusicTable.Files[SndQueue.Ref].Time - break - end - end - if PlayerFound then - --env.info(( 'MusicCanStart: MusicStart = ' .. MusicStart )) - --env.info(( 'MusicCanStart: MusicTime = ' .. MusicTime )) - --env.info(( 'MusicCanStart: timer.getTime() = ' .. timer.getTime() )) - - if MusicStart + MusicTime <= timer.getTime() then - MusicOut = true - end - else - MusicOut = true - end - end - - if MusicOut then - --env.info(( 'MusicCanStart: true' )) - else - --env.info(( 'MusicCanStart: false' )) - end - - return MusicOut -end - -function MusicScheduler() ---trace.scheduled("", "MusicScheduler") - - --env.info(( 'MusicScheduler:' )) - if _MusicTable['Queue'] ~= nil and _MusicTable.FileCnt > 0 then - --env.info(( 'MusicScheduler: Walking Sound Queue.')) - for SndQueueIdx, SndQueue in pairs( _MusicTable.Queue ) do - if SndQueue.Continue then - if MusicCanStart(SndQueue.PlayerName) then - --env.info(('MusicScheduler: MusicToGroup')) - MusicToPlayer( '', SndQueue.PlayerName, true ) - end - end - end - end - -end - - -env.info(( 'Init: Scripts Loaded v1.1' )) - ---- This module contains derived utilities taken from the MIST framework, --- which are excellent tools to be reused in an OO environment!. --- --- ### Authors: --- --- * Grimes : Design & Programming of the MIST framework. --- --- ### Contributions: --- --- * FlightControl : Rework to OO framework --- --- @module Utils - - ---- @type SMOKECOLOR --- @field Green --- @field Red --- @field White --- @field Orange --- @field Blue - -SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR - ---- @type FLARECOLOR --- @field Green --- @field Red --- @field White --- @field Yellow - -FLARECOLOR = trigger.flareColor -- #FLARECOLOR - ---- Utilities static class. --- @type UTILS -UTILS = {} - - ---from http://lua-users.org/wiki/CopyTable -UTILS.DeepCopy = function(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - local objectreturn = _copy(object) - return objectreturn -end - - --- porting in Slmod's serialize_slmod2 -UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - - lookup_table = {} - - local function _Serialize( tbl ) - - if type(tbl) == 'table' then --function only works for tables! - - if lookup_table[tbl] then - return lookup_table[object] - end - - local tbl_str = {} - - lookup_table[tbl] = tbl_str - - tbl_str[#tbl_str + 1] = '{' - - for ind,val in pairs(tbl) do -- serialize its fields - local ind_str = {} - if type(ind) == "number" then - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = tostring(ind) - ind_str[#ind_str + 1] = ']=' - else --must be a string - ind_str[#ind_str + 1] = '[' - ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind) - ind_str[#ind_str + 1] = ']=' - end - - local val_str = {} - if ((type(val) == 'number') or (type(val) == 'boolean')) then - val_str[#val_str + 1] = tostring(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'string' then - val_str[#val_str + 1] = routines.utils.basicSerialize(val) - val_str[#val_str + 1] = ',' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'nil' then -- won't ever happen, right? - val_str[#val_str + 1] = 'nil,' - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - elseif type(val) == 'table' then - if ind == "__index" then - -- tbl_str[#tbl_str + 1] = "__index" - -- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - - val_str[#val_str + 1] = _Serialize(val) - val_str[#val_str + 1] = ',' --I think this is right, I just added it - tbl_str[#tbl_str + 1] = table.concat(ind_str) - tbl_str[#tbl_str + 1] = table.concat(val_str) - end - elseif type(val) == 'function' then - tbl_str[#tbl_str + 1] = "f() " .. tostring(ind) - tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) - env.info( debug.traceback() ) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) - else - return tostring(tbl) - end - end - - local objectreturn = _Serialize(tbl) - return objectreturn -end - ---porting in Slmod's "safestring" basic serialize -UTILS.BasicSerialize = function(s) - if s == nil then - return "\"\"" - else - if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then - return tostring(s) - elseif type(s) == 'string' then - s = string.format('%q', s) - return s - end - end -end - - -UTILS.ToDegree = function(angle) - return angle*180/math.pi -end - -UTILS.ToRadian = function(angle) - return angle*math.pi/180 -end - -UTILS.MetersToNM = function(meters) - return meters/1852 -end - -UTILS.MetersToFeet = function(meters) - return meters/0.3048 -end - -UTILS.NMToMeters = function(NM) - return NM*1852 -end - -UTILS.FeetToMeters = function(feet) - return feet*0.3048 -end - -UTILS.MpsToKnots = function(mps) - return mps*3600/1852 -end - -UTILS.MpsToKmph = function(mps) - return mps*3.6 -end - -UTILS.KnotsToMps = function(knots) - return knots*1852/3600 -end - -UTILS.KmphToMps = function(kmph) - return kmph/3.6 -end - ---[[acc: -in DM: decimal point of minutes. -In DMS: decimal point of seconds. -position after the decimal of the least significant digit: -So: -42.32 - acc of 2. -]] -UTILS.tostringLL = function( lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = UTILS.Round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - - else -- degrees, decimal minutes. - latMin = UTILS.Round(latMin, acc) - lonMin = UTILS.Round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end -end - - ---- From http://lua-users.org/wiki/SimpleRound --- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place -function UTILS.Round( num, idp ) - local mult = 10 ^ ( idp or 0 ) - return math.floor( num * mult + 0.5 ) / mult -end - --- porting in Slmod's dostring -function UTILS.DoString( s ) - local f, err = loadstring( s ) - if f then - return true, f() - else - return false, err - end -end ---- This module contains the BASE class. --- --- 1) @{#BASE} class --- ================= --- The @{#BASE} class is the super class for all the classes defined within MOOSE. --- --- It handles: --- --- * The construction and inheritance of child classes. --- * The tracing of objects during mission execution within the **DCS.log** file, under the **"Saved Games\DCS\Logs"** folder. --- --- Note: Normally you would not use the BASE class unless you are extending the MOOSE framework with new classes. --- --- ## 1.1) BASE constructor --- --- Any class derived from BASE, must use the @{Core.Base#BASE.New) constructor within the @{Core.Base#BASE.Inherit) method. --- See an example at the @{Core.Base#BASE.New} method how this is done. --- --- ## 1.2) BASE Trace functionality --- --- The BASE class contains trace methods to trace progress within a mission execution of a certain object. --- Note that these trace methods are inherited by each MOOSE class interiting BASE. --- As such, each object created from derived class from BASE can use the tracing functions to trace its execution. --- --- ### 1.2.1) Tracing functions --- --- There are basically 3 types of tracing methods available within BASE: --- --- * @{#BASE.F}: Trace the beginning of a function and its given parameters. An F is indicated at column 44 in the DCS.log file. --- * @{#BASE.T}: Trace further logic within a function giving optional variables or parameters. A T is indicated at column 44 in the DCS.log file. --- * @{#BASE.E}: Trace an exception within a function giving optional variables or parameters. An E is indicated at column 44 in the DCS.log file. An exception will always be traced. --- --- ### 1.2.2) Tracing levels --- --- There are 3 tracing levels within MOOSE. --- These tracing levels were defined to avoid bulks of tracing to be generated by lots of objects. --- --- As such, the F and T methods have additional variants to trace level 2 and 3 respectively: --- --- * @{#BASE.F2}: Trace the beginning of a function and its given parameters with tracing level 2. --- * @{#BASE.F3}: Trace the beginning of a function and its given parameters with tracing level 3. --- * @{#BASE.T2}: Trace further logic within a function giving optional variables or parameters with tracing level 2. --- * @{#BASE.T3}: Trace further logic within a function giving optional variables or parameters with tracing level 3. --- --- ### 1.2.3) Trace activation. --- --- Tracing can be activated in several ways: --- --- * Switch tracing on or off through the @{#BASE.TraceOnOff}() method. --- * Activate all tracing through the @{#BASE.TraceAll}() method. --- * Activate only the tracing of a certain class (name) through the @{#BASE.TraceClass}() method. --- * Activate only the tracing of a certain method of a certain class through the @{#BASE.TraceClassMethod}() method. --- * Activate only the tracing of a certain level through the @{#BASE.TraceLevel}() method. --- ### 1.2.4) Check if tracing is on. --- --- The method @{#BASE.IsTrace}() will validate if tracing is activated or not. --- --- ## 1.3 DCS simulator Event Handling --- --- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, --- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently. --- Therefore, the BASE class exposes the following event handling functions: --- --- * @{#BASE.EventOnBirth}(): Handle the birth of a new unit. --- * @{#BASE.EventOnBaseCaptured}(): Handle the capturing of an airbase or a helipad. --- * @{#BASE.EventOnCrash}(): Handle the crash of a unit. --- * @{#BASE.EventOnDead}(): Handle the death of a unit. --- * @{#BASE.EventOnEjection}(): Handle the ejection of a player out of an airplane. --- * @{#BASE.EventOnEngineShutdown}(): Handle the shutdown of an engine. --- * @{#BASE.EventOnEngineStartup}(): Handle the startup of an engine. --- * @{#BASE.EventOnHit}(): Handle the hit of a shell to a unit. --- * @{#BASE.EventOnHumanFailure}(): No a clue ... --- * @{#BASE.EventOnLand}(): Handle the event when a unit lands. --- * @{#BASE.EventOnMissionStart}(): Handle the start of the mission. --- * @{#BASE.EventOnPilotDead}(): Handle the event when a pilot is dead. --- * @{#BASE.EventOnPlayerComment}(): Handle the event when a player posts a comment. --- * @{#BASE.EventOnPlayerEnterUnit}(): Handle the event when a player enters a unit. --- * @{#BASE.EventOnPlayerLeaveUnit}(): Handle the event when a player leaves a unit. --- * @{#BASE.EventOnBirthPlayerMissionEnd}(): Handle the event when a player ends the mission. (Not a clue what that does). --- * @{#BASE.EventOnRefueling}(): Handle the event when a unit is refueling. --- * @{#BASE.EventOnShootingEnd}(): Handle the event when a unit starts shooting (guns). --- * @{#BASE.EventOnShootingStart}(): Handle the event when a unit ends shooting (guns). --- * @{#BASE.EventOnShot}(): Handle the event when a unit shot a missile. --- * @{#BASE.EventOnTakeOff}(): Handle the event when a unit takes off from a runway. --- * @{#BASE.EventOnTookControl}(): Handle the event when a player takes control of a unit. --- --- The EventOn() methods provide the @{Core.Event#EVENTDATA} structure to the event handling function. --- The @{Core.Event#EVENTDATA} structure contains an enriched data set of information about the event being handled. --- --- Find below an example of the prototype how to write an event handling function: --- --- CommandCenter:EventOnPlayerEnterUnit( --- --- @param #COMMANDCENTER self --- -- @param Core.Event#EVENTDATA EventData --- function( self, EventData ) --- local PlayerUnit = EventData.IniUnit --- for MissionID, Mission in pairs( self:GetMissions() ) do --- local Mission = Mission -- Tasking.Mission#MISSION --- Mission:JoinUnit( PlayerUnit ) --- Mission:ReportDetails() --- end --- end --- ) --- --- Note the function( self, EventData ). It takes two parameters: --- --- * self = the object that is handling the EventOnPlayerEnterUnit. --- * EventData = the @{Core.Event#EVENTDATA} structure, containing more information of the Event. --- --- ## 1.4) Class identification methods --- --- BASE provides methods to get more information of each object: --- --- * @{#BASE.GetClassID}(): Gets the ID (number) of the object. Each object created is assigned a number, that is incremented by one. --- * @{#BASE.GetClassName}(): Gets the name of the object, which is the name of the class the object was instantiated from. --- * @{#BASE.GetClassNameAndID}(): Gets the name and ID of the object. --- --- ## 1.10) BASE Inheritance (tree) support --- --- The following methods are available to support inheritance: --- --- * @{#BASE.Inherit}: Inherits from a class. --- * @{#BASE.GetParent}: Returns the parent object from the object it is handling, or nil if there is no parent object. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) --- YYYY-MM-DD: CLASS:**NewFunction( Params )** added --- --- Hereby the change log: --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * None. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming --- --- @module Base - - - -local _TraceOnOff = true -local _TraceLevel = 1 -local _TraceAll = false -local _TraceClass = {} -local _TraceClassMethod = {} - -local _ClassID = 0 - ---- The BASE Class --- @type BASE --- @field ClassName The name of the class. --- @field ClassID The ID number of the class. --- @field ClassNameAndID The name of the class concatenated with the ID number of the class. -BASE = { - ClassName = "BASE", - ClassID = 0, - Events = {}, - States = {} -} - ---- The Formation Class --- @type FORMATION --- @field Cone A cone formation. -FORMATION = { - Cone = "Cone" -} - - - --- @todo need to investigate if the deepCopy is really needed... Don't think so. -function BASE:New() - local self = routines.utils.deepCopy( self ) -- Create a new self instance - local MetaTable = {} - setmetatable( self, MetaTable ) - self.__index = self - _ClassID = _ClassID + 1 - self.ClassID = _ClassID - - - return self -end - -function BASE:_Destructor() - --self:E("_Destructor") - - --self:EventRemoveAll() -end - -function BASE:_SetDestructor() - - -- TODO: Okay, this is really technical... - -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak... - -- Therefore, I am parking this logic until I've properly discussed all this with the community. - --[[ - local proxy = newproxy(true) - local proxyMeta = getmetatable(proxy) - - proxyMeta.__gc = function () - env.info("In __gc for " .. self:GetClassNameAndID() ) - if self._Destructor then - self:_Destructor() - end - end - - -- keep the userdata from newproxy reachable until the object - -- table is about to be garbage-collected - then the __gc hook - -- will be invoked and the destructor called - rawset( self, '__proxy', proxy ) - --]] -end - ---- This is the worker method to inherit from a parent class. --- @param #BASE self --- @param Child is the Child class that inherits. --- @param #BASE Parent is the Parent class that the Child inherits from. --- @return #BASE Child -function BASE:Inherit( Child, Parent ) - local Child = routines.utils.deepCopy( Child ) - --local Parent = routines.utils.deepCopy( Parent ) - --local Parent = Parent - if Child ~= nil then - setmetatable( Child, Parent ) - Child.__index = Child - - Child:_SetDestructor() - end - --self:T( 'Inherited from ' .. Parent.ClassName ) - return Child -end - ---- This is the worker method to retrieve the Parent class. --- @param #BASE self --- @param #BASE Child is the Child class from which the Parent class needs to be retrieved. --- @return #BASE -function BASE:GetParent( Child ) - local Parent = getmetatable( Child ) --- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName ) - return Parent -end - ---- Get the ClassName + ClassID of the class instance. --- The ClassName + ClassID is formatted as '%s#%09d'. --- @param #BASE self --- @return #string The ClassName + ClassID of the class instance. -function BASE:GetClassNameAndID() - return string.format( '%s#%09d', self.ClassName, self.ClassID ) -end - ---- Get the ClassName of the class instance. --- @param #BASE self --- @return #string The ClassName of the class instance. -function BASE:GetClassName() - return self.ClassName -end - ---- Get the ClassID of the class instance. --- @param #BASE self --- @return #string The ClassID of the class instance. -function BASE:GetClassID() - return self.ClassID -end - ---- Set a new listener for the class. --- @param self --- @param Dcs.DCSTypes#Event Event --- @param #function EventFunction --- @return #BASE -function BASE:AddEvent( Event, EventFunction ) - self:F( Event ) - - self.Events[#self.Events+1] = {} - self.Events[#self.Events].Event = Event - self.Events[#self.Events].EventFunction = EventFunction - self.Events[#self.Events].EventEnabled = false - - return self -end - ---- Returns the event dispatcher --- @param #BASE self --- @return Core.Event#EVENT -function BASE:Event() - - return _EVENTDISPATCHER -end - ---- Remove all subscribed events --- @param #BASE self --- @return #BASE -function BASE:EventRemoveAll() - - _EVENTDISPATCHER:RemoveAll( self ) - - return self -end - ---- Subscribe to a S_EVENT\_SHOT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShot( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOT ) - - return self -end - ---- Subscribe to a S_EVENT\_HIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnHit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_HIT ) - - return self -end - ---- Subscribe to a S_EVENT\_TAKEOFF event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnTakeOff( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_TAKEOFF ) - - return self -end - ---- Subscribe to a S_EVENT\_LAND event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnLand( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_LAND ) - - return self -end - ---- Subscribe to a S_EVENT\_CRASH event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnCrash( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_CRASH ) - - return self -end - ---- Subscribe to a S_EVENT\_EJECTION event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEjection( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_EJECTION ) - - return self -end - - ---- Subscribe to a S_EVENT\_REFUELING event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnRefueling( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_REFUELING ) - - return self -end - ---- Subscribe to a S_EVENT\_DEAD event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnDead( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_DEAD ) - - return self -end - ---- Subscribe to a S_EVENT_PILOT\_DEAD event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPilotDead( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PILOT_DEAD ) - - return self -end - ---- Subscribe to a S_EVENT_BASE\_CAPTURED event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnBaseCaptured( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_BASE_CAPTURED ) - - return self -end - ---- Subscribe to a S_EVENT_MISSION\_START event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnMissionStart( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_MISSION_START ) - - return self -end - ---- Subscribe to a S_EVENT_MISSION\_END event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerMissionEnd( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_MISSION_END ) - - return self -end - ---- Subscribe to a S_EVENT_TOOK\_CONTROL event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnTookControl( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_TOOK_CONTROL ) - - return self -end - ---- Subscribe to a S_EVENT_REFUELING\_STOP event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnRefuelingStop( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_REFUELING_STOP ) - - return self -end - ---- Subscribe to a S_EVENT\_BIRTH event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnBirth( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_BIRTH ) - - return self -end - ---- Subscribe to a S_EVENT_HUMAN\_FAILURE event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnHumanFailure( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_HUMAN_FAILURE ) - - return self -end - ---- Subscribe to a S_EVENT_ENGINE\_STARTUP event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEngineStartup( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_ENGINE_STARTUP ) - - return self -end - ---- Subscribe to a S_EVENT_ENGINE\_SHUTDOWN event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnEngineShutdown( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER_ENTER\_UNIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerEnterUnit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER_LEAVE\_UNIT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerLeaveUnit( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self -end - ---- Subscribe to a S_EVENT_PLAYER\_COMMENT event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnPlayerComment( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_PLAYER_COMMENT ) - - return self -end - ---- Subscribe to a S_EVENT_SHOOTING\_START event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShootingStart( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOOTING_START ) - - return self -end - ---- Subscribe to a S_EVENT_SHOOTING\_END event. --- @param #BASE self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @return #BASE -function BASE:EventOnShootingEnd( EventFunction ) - - _EVENTDISPATCHER:OnEventGeneric( EventFunction, self, world.event.S_EVENT_SHOOTING_END ) - - return self -end - - - - - - - ---- Enable the event listeners for the class. --- @param #BASE self --- @return #BASE -function BASE:EnableEvents() - self:F( #self.Events ) - - for EventID, Event in pairs( self.Events ) do - Event.Self = self - Event.EventEnabled = true - end - self.Events.Handler = world.addEventHandler( self ) - - return self -end - - ---- Disable the event listeners for the class. --- @param #BASE self --- @return #BASE -function BASE:DisableEvents() - self:F() - - world.removeEventHandler( self ) - for EventID, Event in pairs( self.Events ) do - Event.Self = nil - Event.EventEnabled = false - end - - return self -end - - -local BaseEventCodes = { - "S_EVENT_SHOT", - "S_EVENT_HIT", - "S_EVENT_TAKEOFF", - "S_EVENT_LAND", - "S_EVENT_CRASH", - "S_EVENT_EJECTION", - "S_EVENT_REFUELING", - "S_EVENT_DEAD", - "S_EVENT_PILOT_DEAD", - "S_EVENT_BASE_CAPTURED", - "S_EVENT_MISSION_START", - "S_EVENT_MISSION_END", - "S_EVENT_TOOK_CONTROL", - "S_EVENT_REFUELING_STOP", - "S_EVENT_BIRTH", - "S_EVENT_HUMAN_FAILURE", - "S_EVENT_ENGINE_STARTUP", - "S_EVENT_ENGINE_SHUTDOWN", - "S_EVENT_PLAYER_ENTER_UNIT", - "S_EVENT_PLAYER_LEAVE_UNIT", - "S_EVENT_PLAYER_COMMENT", - "S_EVENT_SHOOTING_START", - "S_EVENT_SHOOTING_END", - "S_EVENT_MAX", -} - ---onEvent( {[1]="S_EVENT_BIRTH",[2]={["subPlace"]=5,["time"]=0,["initiator"]={["id_"]=16884480,},["place"]={["id_"]=5000040,},["id"]=15,["IniUnitName"]="US F-15C@RAMP-Air Support Mountains#001-01",},} --- Event = { --- id = enum world.event, --- time = Time, --- initiator = Unit, --- target = Unit, --- place = Unit, --- subPlace = enum world.BirthPlace, --- weapon = Weapon --- } - ---- Creation of a Birth Event. --- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. --- @param #string IniUnitName The initiating unit name. --- @param place --- @param subplace -function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace ) - self:F( { EventTime, Initiator, IniUnitName, place, subplace } ) - - local Event = { - id = world.event.S_EVENT_BIRTH, - time = EventTime, - initiator = Initiator, - IniUnitName = IniUnitName, - place = place, - subplace = subplace - } - - world.onEvent( Event ) -end - ---- Creation of a Crash Event. --- @param #BASE self --- @param Dcs.DCSTypes#Time EventTime The time stamp of the event. --- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event. -function BASE:CreateEventCrash( EventTime, Initiator ) - self:F( { EventTime, Initiator } ) - - local Event = { - id = world.event.S_EVENT_CRASH, - time = EventTime, - initiator = Initiator, - } - - world.onEvent( Event ) -end - --- TODO: Complete Dcs.DCSTypes#Event structure. ---- The main event handling function... This function captures all events generated for the class. --- @param #BASE self --- @param Dcs.DCSTypes#Event event -function BASE:onEvent(event) - --self:F( { BaseEventCodes[event.id], event } ) - - if self then - for EventID, EventObject in pairs( self.Events ) do - if EventObject.EventEnabled then - --env.info( 'onEvent Table EventObject.Self = ' .. tostring(EventObject.Self) ) - --env.info( 'onEvent event.id = ' .. tostring(event.id) ) - --env.info( 'onEvent EventObject.Event = ' .. tostring(EventObject.Event) ) - if event.id == EventObject.Event then - if self == EventObject.Self then - if event.initiator and event.initiator:isExist() then - event.IniUnitName = event.initiator:getName() - end - if event.target and event.target:isExist() then - event.TgtUnitName = event.target:getName() - end - --self:T( { BaseEventCodes[event.id], event } ) - --EventObject.EventFunction( self, event ) - end - end - end - end - end -end - -function BASE:SetState( Object, StateName, State ) - - local ClassNameAndID = Object:GetClassNameAndID() - - self.States[ClassNameAndID] = self.States[ClassNameAndID] or {} - self.States[ClassNameAndID][StateName] = State - self:T2( { ClassNameAndID, StateName, State } ) - - return self.States[ClassNameAndID][StateName] -end - -function BASE:GetState( Object, StateName ) - - local ClassNameAndID = Object:GetClassNameAndID() - - if self.States[ClassNameAndID] then - local State = self.States[ClassNameAndID][StateName] or false - self:T2( { ClassNameAndID, StateName, State } ) - return State - end - - return nil -end - -function BASE:ClearState( Object, StateName ) - - local ClassNameAndID = Object:GetClassNameAndID() - if self.States[ClassNameAndID] then - self.States[ClassNameAndID][StateName] = nil - end -end - --- Trace section - --- Log a trace (only shown when trace is on) --- TODO: Make trace function using variable parameters. - ---- Set trace on or off --- Note that when trace is off, no debug statement is performed, increasing performance! --- When Moose is loaded statically, (as one file), tracing is switched off by default. --- So tracing must be switched on manually in your mission if you are using Moose statically. --- When moose is loading dynamically (for moose class development), tracing is switched on by default. --- @param #BASE self --- @param #boolean TraceOnOff Switch the tracing on or off. --- @usage --- -- Switch the tracing On --- BASE:TraceOnOff( true ) --- --- -- Switch the tracing Off --- BASE:TraceOnOff( false ) -function BASE:TraceOnOff( TraceOnOff ) - _TraceOnOff = TraceOnOff -end - - ---- Enquires if tracing is on (for the class). --- @param #BASE self --- @return #boolean -function BASE:IsTrace() - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - return true - else - return false - end -end - ---- Set trace level --- @param #BASE self --- @param #number Level -function BASE:TraceLevel( Level ) - _TraceLevel = Level - self:E( "Tracing level " .. Level ) -end - ---- Trace all methods in MOOSE --- @param #BASE self --- @param #boolean TraceAll true = trace all methods in MOOSE. -function BASE:TraceAll( TraceAll ) - - _TraceAll = TraceAll - - if _TraceAll then - self:E( "Tracing all methods in MOOSE " ) - else - self:E( "Switched off tracing all methods in MOOSE" ) - end -end - ---- Set tracing for a class --- @param #BASE self --- @param #string Class -function BASE:TraceClass( Class ) - _TraceClass[Class] = true - _TraceClassMethod[Class] = {} - self:E( "Tracing class " .. Class ) -end - ---- Set tracing for a specific method of class --- @param #BASE self --- @param #string Class --- @param #string Method -function BASE:TraceClassMethod( Class, Method ) - if not _TraceClassMethod[Class] then - _TraceClassMethod[Class] = {} - _TraceClassMethod[Class].Method = {} - end - _TraceClassMethod[Class].Method[Method] = true - self:E( "Tracing method " .. Method .. " of class " .. Class ) -end - ---- Trace a function call. This function is private. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - - local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) - local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then - local LineCurrent = 0 - if DebugInfoCurrent.currentline then - LineCurrent = DebugInfoCurrent.currentline - end - local LineFrom = 0 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) - end - end -end - ---- Trace a function call. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 1 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - - ---- Trace a function call level 2. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F2( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 2 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function call level 3. Must be at the beginning of the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:F3( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 3 then - self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - - if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then - - local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" ) - local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then - local LineCurrent = 0 - if DebugInfoCurrent.currentline then - LineCurrent = DebugInfoCurrent.currentline - end - local LineFrom = 0 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) - end - end -end - ---- Trace a function logic level 1. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 1 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - - ---- Trace a function logic level 2. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T2( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 2 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Trace a function logic level 3. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:T3( Arguments ) - - if debug and _TraceOnOff then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - if _TraceLevel >= 3 then - self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom ) - end - end -end - ---- Log an exception which will be traced always. Can be anywhere within the function logic. --- @param #BASE self --- @param Arguments A #table or any field. -function BASE:E( Arguments ) - - if debug then - local DebugInfoCurrent = debug.getinfo( 2, "nl" ) - local DebugInfoFrom = debug.getinfo( 3, "l" ) - - local Function = "function" - if DebugInfoCurrent.name then - Function = DebugInfoCurrent.name - end - - local LineCurrent = DebugInfoCurrent.currentline - local LineFrom = -1 - if DebugInfoFrom then - LineFrom = DebugInfoFrom.currentline - end - - env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) - end - -end - - - ---- This module contains the SCHEDULER class. --- --- # 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE} --- --- The @{Core.Scheduler#SCHEDULER} class creates schedule. --- --- ## 1.1) SCHEDULER constructor --- --- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters: --- --- * @{Core.Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection. --- * @{Core.Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection. --- * @{Core.Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- * @{Core.Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters. --- --- ## 1.2) SCHEDULER timer stopping and (re-)starting. --- --- The SCHEDULER can be stopped and restarted with the following methods: --- --- * @{Core.Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started. --- * @{Core.Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped. --- --- ## 1.3) Create a new schedule --- --- With @{Core.Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned. --- --- === --- --- ### Contributions: --- --- * FlightControl : Concept & Testing --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Test Missions: --- --- * SCH - Scheduler --- --- === --- --- @module Scheduler - - ---- The SCHEDULER class --- @type SCHEDULER --- @field #number ScheduleID the ID of the scheduler. --- @extends Core.Base#BASE -SCHEDULER = { - ClassName = "SCHEDULER", - Schedules = {}, -} - ---- SCHEDULER constructor. --- @param #SCHEDULER self --- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. --- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. --- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. --- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. --- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. --- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. --- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. --- @return #SCHEDULER self --- @return #number The ScheduleID of the planned schedule. -function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( { Start, Repeat, RandomizeFactor, Stop } ) - - local ScheduleID = nil - - self.MasterObject = SchedulerObject - - if SchedulerFunction then - ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - end - - return self, ScheduleID -end - ---function SCHEDULER:_Destructor() --- --self:E("_Destructor") --- --- _SCHEDULEDISPATCHER:RemoveSchedule( self.CallID ) ---end - ---- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also. --- @param #SCHEDULER self --- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. --- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. --- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. --- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. --- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function. --- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. --- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped. --- @return #number The ScheduleID of the planned schedule. -function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) - self:F2( { Start, Repeat, RandomizeFactor, Stop } ) - self:T3( { SchedulerArguments } ) - - local ObjectName = "-" - if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then - ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID - end - self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) - self.SchedulerObject = SchedulerObject - - local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( - self, - SchedulerFunction, - SchedulerArguments, - Start, - Repeat, - RandomizeFactor, - Stop - ) - - self.Schedules[#self.Schedules+1] = ScheduleID - - return ScheduleID -end - ---- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Start( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Start( self, ScheduleID ) -end - ---- Stops the schedules or a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Stop( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Stop( self, ScheduleID ) -end - ---- Removes a specific schedule if a valid ScheduleID is provided. --- @param #SCHEDULER self --- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule. -function SCHEDULER:Remove( ScheduleID ) - self:F3( { ScheduleID } ) - - _SCHEDULEDISPATCHER:Remove( self, ScheduleID ) -end - - - - - - - - - - - - - - - ---- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER. --- --- === --- --- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects. --- --- This class is tricky and needs some thorought explanation. --- SCHEDULE classes are used to schedule functions for objects, or as persistent objects. --- The SCHEDULEDISPATCHER class ensures that: --- --- - Scheduled functions are planned according the SCHEDULER object parameters. --- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters. --- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters. --- --- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection: --- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER --- object is _persistent_ within memory. --- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection! --- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected. --- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object, --- these will not be executed anymore when the SCHEDULER object has been destroyed. --- --- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object. --- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER. --- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method. --- The Schedule() method returns the CallID that is the reference ID for each planned schedule. --- --- === --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module ScheduleDispatcher - ---- The SCHEDULEDISPATCHER structure --- @type SCHEDULEDISPATCHER -SCHEDULEDISPATCHER = { - ClassName = "SCHEDULEDISPATCHER", - CallID = 0, -} - -function SCHEDULEDISPATCHER:New() - local self = BASE:Inherit( self, BASE:New() ) - self:F3() - return self -end - ---- Add a Schedule to the ScheduleDispatcher. --- The development of this method was really tidy. --- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified. --- Nothing of this code should be modified without testing it thoroughly. --- @param #SCHEDULEDISPATCHER self --- @param Core.Scheduler#SCHEDULER Scheduler -function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop ) - self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } ) - - self.CallID = self.CallID + 1 - - -- Initialize the ObjectSchedulers array, which is a weakly coupled table. - -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.PersistentSchedulers = self.PersistentSchedulers or {} - - -- Initialize the ObjectSchedulers array, which is a weakly coupled table. - -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) - - if Scheduler.MasterObject then - self.ObjectSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } ) - else - self.PersistentSchedulers[self.CallID] = Scheduler - self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) - end - - self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) - self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} - self.Schedule[Scheduler][self.CallID] = {} - self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction - self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments - self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 ) - self.Schedule[Scheduler][self.CallID].Start = Start + .1 - self.Schedule[Scheduler][self.CallID].Repeat = Repeat - self.Schedule[Scheduler][self.CallID].Randomize = Randomize - self.Schedule[Scheduler][self.CallID].Stop = Stop - - self:T3( self.Schedule[Scheduler][self.CallID] ) - - self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID ) - self:F2( CallID ) - - local ErrorHandler = function( errmsg ) - env.info( "Error in timer function: " .. errmsg ) - if debug ~= nil then - env.info( debug.traceback() ) - end - return errmsg - end - - local Scheduler = self.ObjectSchedulers[CallID] - if not Scheduler then - Scheduler = self.PersistentSchedulers[CallID] - end - - self:T3( { Scheduler = Scheduler } ) - - if Scheduler then - - local Schedule = self.Schedule[Scheduler][CallID] - - self:T3( { Schedule = Schedule } ) - - local ScheduleObject = Scheduler.SchedulerObject - --local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID() - local ScheduleFunction = Schedule.Function - local ScheduleArguments = Schedule.Arguments - local Start = Schedule.Start - local Repeat = Schedule.Repeat or 0 - local Randomize = Schedule.Randomize or 0 - local Stop = Schedule.Stop or 0 - local ScheduleID = Schedule.ScheduleID - - local Status, Result - if ScheduleObject then - local function Timer() - return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) ) - end - Status, Result = xpcall( Timer, ErrorHandler ) - else - local function Timer() - return ScheduleFunction( unpack( ScheduleArguments ) ) - end - Status, Result = xpcall( Timer, ErrorHandler ) - end - - local CurrentTime = timer.getTime() - local StartTime = CurrentTime + Start - - 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 - local ScheduleTime = - CurrentTime + - Repeat + - math.random( - - ( Randomize * Repeat / 2 ), - ( Randomize * Repeat / 2 ) - ) + - 0.01 - self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } ) - return ScheduleTime -- returns the next time the function needs to be called. - else - self:Stop( Scheduler, CallID ) - end - else - self:Stop( Scheduler, CallID ) - end - else - self:E( "Scheduled obscolete call for CallID: " .. CallID ) - end - - return nil - end - - self:Start( Scheduler, self.CallID ) - - return self.CallID -end - -function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID ) - self:F2( { Remove = CallID, Scheduler = Scheduler } ) - - if CallID then - self:Stop( Scheduler, CallID ) - self.Schedule[Scheduler][CallID] = nil - end -end - -function SCHEDULEDISPATCHER:Start( Scheduler, CallID ) - self:F2( { Start = CallID, Scheduler = Scheduler } ) - - if CallID then - local Schedule = self.Schedule[Scheduler] - Schedule[CallID].ScheduleID = timer.scheduleFunction( - Schedule[CallID].CallHandler, - CallID, - timer.getTime() + Schedule[CallID].Start - ) - else - for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do - self:Start( Scheduler, CallID ) -- Recursive - end - end -end - -function SCHEDULEDISPATCHER:Stop( Scheduler, CallID ) - self:F2( { Stop = CallID, Scheduler = Scheduler } ) - - if CallID then - local Schedule = self.Schedule[Scheduler] - timer.removeFunction( Schedule[CallID].ScheduleID ) - else - for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do - self:Stop( Scheduler, CallID ) -- Recursive - end - end -end - - - ---- This module contains the EVENT class. --- --- === --- --- Takes care of EVENT dispatching between DCS events and event handling functions defined in MOOSE classes. --- --- === --- --- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these): --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module Event - ---- The EVENT structure --- @type EVENT --- @field #EVENT.Events Events -EVENT = { - ClassName = "EVENT", - ClassID = 0, -} - -local _EVENTCODES = { - "S_EVENT_SHOT", - "S_EVENT_HIT", - "S_EVENT_TAKEOFF", - "S_EVENT_LAND", - "S_EVENT_CRASH", - "S_EVENT_EJECTION", - "S_EVENT_REFUELING", - "S_EVENT_DEAD", - "S_EVENT_PILOT_DEAD", - "S_EVENT_BASE_CAPTURED", - "S_EVENT_MISSION_START", - "S_EVENT_MISSION_END", - "S_EVENT_TOOK_CONTROL", - "S_EVENT_REFUELING_STOP", - "S_EVENT_BIRTH", - "S_EVENT_HUMAN_FAILURE", - "S_EVENT_ENGINE_STARTUP", - "S_EVENT_ENGINE_SHUTDOWN", - "S_EVENT_PLAYER_ENTER_UNIT", - "S_EVENT_PLAYER_LEAVE_UNIT", - "S_EVENT_PLAYER_COMMENT", - "S_EVENT_SHOOTING_START", - "S_EVENT_SHOOTING_END", - "S_EVENT_MAX", -} - ---- The Event structure --- @type EVENTDATA --- @field id --- @field initiator --- @field target --- @field weapon --- @field IniDCSUnit --- @field IniDCSUnitName --- @field Wrapper.Unit#UNIT IniUnit --- @field #string IniUnitName --- @field IniDCSGroup --- @field IniDCSGroupName --- @field TgtDCSUnit --- @field TgtDCSUnitName --- @field Wrapper.Unit#UNIT TgtUnit --- @field #string TgtUnitName --- @field TgtDCSGroup --- @field TgtDCSGroupName --- @field Weapon --- @field WeaponName --- @field WeaponTgtDCSUnit - ---- The Events structure --- @type EVENT.Events --- @field #number IniUnit - -function EVENT:New() - local self = BASE:Inherit( self, BASE:New() ) - self:F2() - self.EventHandler = world.addEventHandler( self ) - return self -end - -function EVENT:EventText( EventID ) - - local EventText = _EVENTCODES[EventID] - - return EventText -end - - ---- Initializes the Events structure for the event --- @param #EVENT self --- @param Dcs.DCSWorld#world.event EventID --- @param Core.Base#BASE EventClass --- @return #EVENT.Events -function EVENT:Init( EventID, EventClass ) - self:F3( { _EVENTCODES[EventID], EventClass } ) - - if not self.Events[EventID] then - -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. - self.Events[EventID] = setmetatable( {}, { __mode = "k" } ) - - end - - if not self.Events[EventID][EventClass] then - self.Events[EventID][EventClass] = setmetatable( {}, { __mode = "k" } ) - end - return self.Events[EventID][EventClass] -end - ---- Removes an Events entry --- @param #EVENT self --- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param Dcs.DCSWorld#world.event EventID --- @return #EVENT.Events -function EVENT:Remove( EventClass, EventID ) - self:F3( { EventClass, _EVENTCODES[EventID] } ) - - local EventClass = EventClass - self.Events[EventID][EventClass] = nil -end - ---- Clears all event subscriptions for a @{Core.Base#BASE} derived object. --- @param #EVENT self --- @param Core.Base#BASE EventObject -function EVENT:RemoveAll( EventObject ) - self:F3( { EventObject:GetClassNameAndID() } ) - - local EventClass = EventObject:GetClassNameAndID() - for EventID, EventData in pairs( self.Events ) do - self.Events[EventID][EventClass] = nil - end -end - - - ---- Create an OnDead event handler for a group --- @param #EVENT self --- @param #table EventTemplate --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param EventClass The instance of the class for which the event is. --- @param #function OnEventFunction --- @return #EVENT -function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, OnEventFunction ) - self:F2( EventTemplate.name ) - - for EventUnitID, EventUnit in pairs( EventTemplate.units ) do - OnEventFunction( self, EventUnit.name, EventFunction, EventClass ) - end - return self -end - ---- Set a new listener for an S_EVENT_X event independent from a unit or a weapon. --- @param #EVENT self --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param Core.Base#BASE EventClass The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided. --- @param EventID --- @return #EVENT -function EVENT:OnEventGeneric( EventFunction, EventClass, EventID ) - self:F2( { EventID } ) - - local Event = self:Init( EventID, EventClass ) - Event.EventFunction = EventFunction - Event.EventClass = EventClass - return self -end - - ---- Set a new listener for an S_EVENT_X event --- @param #EVENT self --- @param #string EventDCSUnitName --- @param #function EventFunction The function to be called when the event occurs for the unit. --- @param Core.Base#BASE EventClass The self instance of the class for which the event is. --- @param EventID --- @return #EVENT -function EVENT:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, EventID ) - self:F2( EventDCSUnitName ) - - local Event = self:Init( EventID, EventClass ) - if not Event.IniUnit then - Event.IniUnit = {} - end - Event.IniUnit[EventDCSUnitName] = {} - Event.IniUnit[EventDCSUnitName].EventFunction = EventFunction - Event.IniUnit[EventDCSUnitName].EventClass = EventClass - return self -end - -do -- OnBirth - - --- Create an OnBirth event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnBirthForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_BIRTH event, and registers the unit born. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirth( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - --- Set a new listener for an S_EVENT_BIRTH event. - -- @param #EVENT self - -- @param #string EventDCSUnitName The id of the unit for the event to be handled. - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirthForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - --- Stop listening to S_EVENT_BIRTH event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnBirthRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_BIRTH ) - - return self - end - - -end - -do -- OnCrash - - --- Create an OnCrash event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnCrashForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_CRASH event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnCrash( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_CRASH ) - - return self - end - - --- Set a new listener for an S_EVENT_CRASH event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnCrashForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_CRASH ) - - return self - end - - --- Stop listening to S_EVENT_CRASH event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnCrashRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_CRASH ) - - return self - end - -end - -do -- OnDead - - --- Create an OnDead event handler for a group - -- @param #EVENT self - -- @param Wrapper.Group#GROUP EventGroup - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnDeadForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_DEAD event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnDead( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - - --- Set a new listener for an S_EVENT_DEAD event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnDeadForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - --- Stop listening to S_EVENT_DEAD event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnDeadRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_DEAD ) - - return self - end - - -end - -do -- OnPilotDead - - --- Set a new listener for an S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPilotDead( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - - --- Set a new listener for an S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPilotDeadForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - - --- Stop listening to S_EVENT_PILOT_DEAD event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPilotDeadRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PILOT_DEAD ) - - return self - end - -end - -do -- OnLand - --- Create an OnLand event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnLandForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_LAND event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnLandForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_LAND ) - - return self - end - - --- Stop listening to S_EVENT_LAND event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnLandRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_LAND ) - - return self - end - - -end - -do -- OnTakeOff - --- Create an OnTakeOff event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnTakeOffForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_TAKEOFF event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnTakeOffForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_TAKEOFF ) - - return self - end - - --- Stop listening to S_EVENT_TAKEOFF event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnTakeOffRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_TAKEOFF ) - - return self - end - - -end - -do -- OnEngineShutDown - - --- Create an OnDead event handler for a group - -- @param #EVENT self - -- @param #table EventTemplate - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventClass ) - self:F2( EventTemplate.name ) - - self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, self.OnEngineShutDownForUnit ) - - return self - end - - --- Set a new listener for an S_EVENT_ENGINE_SHUTDOWN event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineShutDownForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self - end - - --- Stop listening to S_EVENT_ENGINE_SHUTDOWN event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnEngineShutDownRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_ENGINE_SHUTDOWN ) - - return self - end - -end - -do -- OnEngineStartUp - - --- Set a new listener for an S_EVENT_ENGINE_STARTUP event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnEngineStartUpForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_ENGINE_STARTUP ) - - return self - end - - --- Stop listening to S_EVENT_ENGINE_STARTUP event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnEngineStartUpRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_ENGINE_STARTUP ) - - return self - end - -end - -do -- OnShot - --- Set a new listener for an S_EVENT_SHOT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnShot( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - --- Set a new listener for an S_EVENT_SHOT event for a unit. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnShotForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - --- Stop listening to S_EVENT_SHOT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnShotRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_SHOT ) - - return self - end - - -end - -do -- OnHit - - --- Set a new listener for an S_EVENT_HIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnHit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_HIT ) - - return self - end - - --- Set a new listener for an S_EVENT_HIT event. - -- @param #EVENT self - -- @param #string EventDCSUnitName - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnHitForUnit( EventDCSUnitName, EventFunction, EventClass ) - self:F2( EventDCSUnitName ) - - self:OnEventForUnit( EventDCSUnitName, EventFunction, EventClass, world.event.S_EVENT_HIT ) - - return self - end - - --- Stop listening to S_EVENT_HIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnHitRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_HIT ) - - return self - end - -end - -do -- OnPlayerEnterUnit - - --- Set a new listener for an S_EVENT_PLAYER_ENTER_UNIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPlayerEnterUnit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self - end - - --- Stop listening to S_EVENT_PLAYER_ENTER_UNIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPlayerEnterRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PLAYER_ENTER_UNIT ) - - return self - end - -end - -do -- OnPlayerLeaveUnit - --- Set a new listener for an S_EVENT_PLAYER_LEAVE_UNIT event. - -- @param #EVENT self - -- @param #function EventFunction The function to be called when the event occurs for the unit. - -- @param Base#BASE EventClass The self instance of the class for which the event is. - -- @return #EVENT - function EVENT:OnPlayerLeaveUnit( EventFunction, EventClass ) - self:F2() - - self:OnEventGeneric( EventFunction, EventClass, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self - end - - --- Stop listening to S_EVENT_PLAYER_LEAVE_UNIT event. - -- @param #EVENT self - -- @param Base#BASE EventClass - -- @return #EVENT - function EVENT:OnPlayerLeaveRemove( EventClass ) - self:F2() - - self:Remove( EventClass, world.event.S_EVENT_PLAYER_LEAVE_UNIT ) - - return self - end - -end - - - ---- @param #EVENT self --- @param #EVENTDATA Event -function EVENT:onEvent( Event ) - - if self and self.Events and self.Events[Event.id] then - if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then - Event.IniDCSUnit = Event.initiator - Event.IniDCSGroup = Event.IniDCSUnit:getGroup() - Event.IniDCSUnitName = Event.IniDCSUnit:getName() - Event.IniUnitName = Event.IniDCSUnitName - Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName ) - if not Event.IniUnit then - -- Unit can be a CLIENT. Most likely this will be the case ... - Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true ) - end - Event.IniDCSGroupName = "" - if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then - Event.IniDCSGroupName = Event.IniDCSGroup:getName() - end - end - if Event.target then - if Event.target and Event.target:getCategory() == Object.Category.UNIT then - Event.TgtDCSUnit = Event.target - Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup() - Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() - Event.TgtUnitName = Event.TgtDCSUnitName - Event.TgtUnit = UNIT:FindByName( Event.TgtDCSUnitName ) - Event.TgtDCSGroupName = "" - if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then - Event.TgtDCSGroupName = Event.TgtDCSGroup:getName() - end - end - end - if Event.weapon then - Event.Weapon = Event.weapon - Event.WeaponName = Event.Weapon:getTypeName() - --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() - end - self:E( { _EVENTCODES[Event.id], Event, Event.IniDCSUnitName, Event.TgtDCSUnitName } ) - - -- Okay, we got the event from DCS. Now loop the self.Events[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. - for EventClass, EventData in pairs( self.Events[Event.id] ) do - -- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT. - if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then - self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName } ) - EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventClass, Event ) - else - -- If the EventData is not bound to a specific unit, then call the EventClass EventFunction. - -- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon. - if Event.IniDCSUnit and not EventData.IniUnit then - if EventClass == EventData.EventClass then - self:T( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID() } ) - EventData.EventFunction( EventData.EventClass, Event ) - end - end - end - end - else - self:E( { _EVENTCODES[Event.id], Event } ) - end -end - ---- This module contains the MENU classes. --- --- There is a small note... When you see a class like MENU_COMMAND_COALITION with COMMAND in italic, it acutally represents it like this: `MENU_COMMAND_COALITION`. --- --- === --- --- DCS Menus can be managed using the MENU classes. --- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scanerios where you need to --- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing --- menus is not a easy feat if you have complex menu hierarchies defined. --- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy. --- On top, MOOSE implements **variable parameter** passing for command menus. --- --- There are basically two different MENU class types that you need to use: --- --- ### To manage **main menus**, the classes begin with **MENU_**: --- --- * @{Core.Menu#MENU_MISSION}: Manages main menus for whole mission file. --- * @{Core.Menu#MENU_COALITION}: Manages main menus for whole coalition. --- * @{Core.Menu#MENU_GROUP}: Manages main menus for GROUPs. --- * @{Core.Menu#MENU_CLIENT}: Manages main menus for CLIENTs. This manages menus for units with the skill level "Client". --- --- ### To manage **command menus**, which are menus that allow the player to issue **functions**, the classes begin with **MENU_COMMAND_**: --- --- * @{Core.Menu#MENU_MISSION_COMMAND}: Manages command menus for whole mission file. --- * @{Core.Menu#MENU_COALITION_COMMAND}: Manages command menus for whole coalition. --- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs. --- * @{Core.Menu#MENU_CLIENT_COMMAND}: Manages command menus for CLIENTs. This manages menus for units with the skill level "Client". --- --- === --- --- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these): --- --- 1) MENU_ BASE abstract base classes (don't use them) --- ==================================================== --- The underlying base menu classes are **NOT** to be used within your missions. --- These are simply abstract base classes defining a couple of fields that are used by the --- derived MENU_ classes to manage menus. --- --- 1.1) @{Core.Menu#MENU_BASE} class, extends @{Core.Base#BASE} --- -------------------------------------------------- --- The @{#MENU_BASE} class defines the main MENU class where other MENU classes are derived from. --- --- 1.2) @{Core.Menu#MENU_COMMAND_BASE} class, extends @{Core.Base#BASE} --- ---------------------------------------------------------- --- The @{#MENU_COMMAND_BASE} class defines the main MENU class where other MENU COMMAND_ classes are derived from, in order to set commands. --- --- === --- --- **The next menus define the MENU classes that you can use within your missions.** --- --- 2) MENU MISSION classes --- ====================== --- The underlying classes manage the menus for a complete mission file. --- --- 2.1) @{Menu#MENU_MISSION} class, extends @{Core.Menu#MENU_BASE} --- --------------------------------------------------------- --- The @{Core.Menu#MENU_MISSION} class manages the main menus for a complete mission. --- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}. --- --- 2.2) @{Menu#MENU_MISSION_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------- --- The @{Core.Menu#MENU_MISSION_COMMAND} class manages the command menus for a complete mission, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}. --- --- === --- --- 3) MENU COALITION classes --- ========================= --- The underlying classes manage the menus for whole coalitions. --- --- 3.1) @{Menu#MENU_COALITION} class, extends @{Core.Menu#MENU_BASE} --- ------------------------------------------------------------ --- The @{Core.Menu#MENU_COALITION} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}. --- --- 3.2) @{Menu#MENU_COALITION_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ---------------------------------------------------------------------------- --- The @{Core.Menu#MENU_COALITION_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}. --- --- === --- --- 4) MENU GROUP classes --- ===================== --- The underlying classes manage the menus for groups. Note that groups can be inactive, alive or can be destroyed. --- --- 4.1) @{Menu#MENU_GROUP} class, extends @{Core.Menu#MENU_BASE} --- -------------------------------------------------------- --- The @{Core.Menu#MENU_GROUP} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}. --- --- 4.2) @{Menu#MENU_GROUP_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------ --- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP_COMMAND.Remove}. --- --- === --- --- 5) MENU CLIENT classes --- ====================== --- The underlying classes manage the menus for units with skill level client or player. --- --- 5.1) @{Menu#MENU_CLIENT} class, extends @{Core.Menu#MENU_BASE} --- --------------------------------------------------------- --- The @{Core.Menu#MENU_CLIENT} class manages the main menus for coalitions. --- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}. --- --- 5.2) @{Menu#MENU_CLIENT_COMMAND} class, extends @{Core.Menu#MENU_COMMAND_BASE} --- ------------------------------------------------------------------------- --- The @{Core.Menu#MENU_CLIENT_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution. --- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_COMMAND object and returns you the object reference. --- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT_COMMAND.Remove}. --- --- === --- --- ### Contributions: - --- ### Authors: FlightControl : Design & Programming --- --- @module Menu - - -do -- MENU_BASE - - --- The MENU_BASE class - -- @type MENU_BASE - -- @extends Base#BASE - MENU_BASE = { - ClassName = "MENU_BASE", - MenuPath = nil, - MenuText = "", - MenuParentPath = nil - } - - --- Consructor - function MENU_BASE:New( MenuText, ParentMenu ) - - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, BASE:New() ) - - self.MenuPath = nil - self.MenuText = MenuText - self.MenuParentPath = MenuParentPath - - return self - end - -end - -do -- MENU_COMMAND_BASE - - --- The MENU_COMMAND_BASE class - -- @type MENU_COMMAND_BASE - -- @field #function MenuCallHandler - -- @extends Menu#MENU_BASE - MENU_COMMAND_BASE = { - ClassName = "MENU_COMMAND_BASE", - CommandMenuFunction = nil, - CommandMenuArgument = nil, - MenuCallHandler = nil, - } - - --- Constructor - function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self.CommandMenuFunction = CommandMenuFunction - self.MenuCallHandler = function( CommandMenuArguments ) - self.CommandMenuFunction( unpack( CommandMenuArguments ) ) - end - - return self - end - -end - - -do -- MENU_MISSION - - --- The MENU_MISSION class - -- @type MENU_MISSION - -- @extends Menu#MENU_BASE - MENU_MISSION = { - ClassName = "MENU_MISSION" - } - - --- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file. - -- @param #MENU_MISSION self - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). - -- @return #MENU_MISSION self - function MENU_MISSION:New( MenuText, ParentMenu ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self:F( { MenuText, ParentMenu } ) - - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - self:T( { MenuText } ) - - self.MenuPath = missionCommands.addSubMenu( MenuText, self.MenuParentPath ) - - self:T( { self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - - return self - end - - --- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept! - -- @param #MENU_MISSION self - -- @return #MENU_MISSION self - function MENU_MISSION:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and the sub menus recursively of this MENU_MISSION. - -- @param #MENU_MISSION self - -- @return #nil - function MENU_MISSION:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - missionCommands.removeItem( self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - - return nil - end - -end - -do -- MENU_MISSION_COMMAND - - --- The MENU_MISSION_COMMAND class - -- @type MENU_MISSION_COMMAND - -- @extends Menu#MENU_COMMAND_BASE - MENU_MISSION_COMMAND = { - ClassName = "MENU_MISSION_COMMAND" - } - - --- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters. - -- @param #MENU_MISSION_COMMAND self - -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_MISSION ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. - -- @return #MENU_MISSION_COMMAND self - function MENU_MISSION_COMMAND:New( MenuText, ParentMenu, CommandMenuFunction, ... ) - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { MenuText, CommandMenuFunction, arg } ) - - - self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a radio command item for a coalition - -- @param #MENU_MISSION_COMMAND self - -- @return #nil - function MENU_MISSION_COMMAND:Remove() - self:F( self.MenuPath ) - - missionCommands.removeItem( self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - return nil - end - -end - - - -do -- MENU_COALITION - - --- The MENU_COALITION class - -- @type MENU_COALITION - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the planes within the red coalition. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- - -- local Plane1 = CLIENT:FindByName( "Plane 1" ) - -- local Plane2 = CLIENT:FindByName( "Plane 2" ) - -- - -- - -- -- This would create a menu for the red coalition under the main DCS "Others" menu. - -- local MenuCoalitionRed = MENU_COALITION:New( coalition.side.RED, "Manage Menus" ) - -- - -- - -- local function ShowStatus( StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- Plane1:Message( StatusText, 15 ) - -- Plane2:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus -- Menu#MENU_COALITION - -- local MenuStatusShow -- Menu#MENU_COALITION_COMMAND - -- - -- local function RemoveStatusMenu() - -- MenuStatus:Remove() - -- end - -- - -- local function AddStatusMenu() - -- - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus = MENU_COALITION:New( coalition.side.RED, "Status for Planes" ) - -- MenuStatusShow = MENU_COALITION_COMMAND:New( coalition.side.RED, "Show Status", MenuStatus, ShowStatus, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- local MenuAdd = MENU_COALITION_COMMAND:New( coalition.side.RED, "Add Status Menu", MenuCoalitionRed, AddStatusMenu ) - -- local MenuRemove = MENU_COALITION_COMMAND:New( coalition.side.RED, "Remove Status Menu", MenuCoalitionRed, RemoveStatusMenu ) - MENU_COALITION = { - ClassName = "MENU_COALITION" - } - - --- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition. - -- @param #MENU_COALITION self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other). - -- @return #MENU_COALITION self - function MENU_COALITION:New( Coalition, MenuText, ParentMenu ) - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - - self:F( { Coalition, MenuText, ParentMenu } ) - - self.Coalition = Coalition - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - self:T( { MenuText } ) - - self.MenuPath = missionCommands.addSubMenuForCoalition( Coalition, MenuText, self.MenuParentPath ) - - self:T( { self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - - return self - end - - --- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept! - -- @param #MENU_COALITION self - -- @return #MENU_COALITION self - function MENU_COALITION:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and the sub menus recursively of this MENU_COALITION. - -- @param #MENU_COALITION self - -- @return #nil - function MENU_COALITION:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - - return nil - end - -end - -do -- MENU_COALITION_COMMAND - - --- The MENU_COALITION_COMMAND class - -- @type MENU_COALITION_COMMAND - -- @extends Menu#MENU_COMMAND_BASE - MENU_COALITION_COMMAND = { - ClassName = "MENU_COALITION_COMMAND" - } - - --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. - -- @param #MENU_COALITION_COMMAND self - -- @param Dcs.DCSCoalition#coalition.side Coalition The coalition owning the menu. - -- @param #string MenuText The text for the menu. - -- @param Menu#MENU_COALITION ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. There can only be ONE argument given. So multiple arguments must be wrapped into a table. See the below example how to do this. - -- @return #MENU_COALITION_COMMAND self - function MENU_COALITION_COMMAND:New( Coalition, MenuText, ParentMenu, CommandMenuFunction, ... ) - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - - self.MenuCoalition = Coalition - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { MenuText, CommandMenuFunction, arg } ) - - - self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a radio command item for a coalition - -- @param #MENU_COALITION_COMMAND self - -- @return #nil - function MENU_COALITION_COMMAND:Remove() - self:F( self.MenuPath ) - - missionCommands.removeItemForCoalition( self.MenuCoalition, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - return nil - end - -end - -do -- MENU_CLIENT - - -- This local variable is used to cache the menus registered under clients. - -- Menus don't dissapear when clients are destroyed and restarted. - -- So every menu for a client created must be tracked so that program logic accidentally does not create - -- the same menus twice during initialization logic. - -- These menu classes are handling this logic with this variable. - local _MENUCLIENTS = {} - - --- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters. - -- @type MENU_CLIENT - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the two clients of planes. - -- -- Each client will receive a different menu structure. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- -- And play with the Add and Remove menu options. - -- - -- -- Note that in multi player, this will only work after the DCS clients bug is solved. - -- - -- local function ShowStatus( PlaneClient, StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- PlaneClient:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus = {} - -- - -- local function RemoveStatusMenu( MenuClient ) - -- local MenuClientName = MenuClient:GetName() - -- MenuStatus[MenuClientName]:Remove() - -- end - -- - -- --- @param Wrapper.Client#CLIENT MenuClient - -- local function AddStatusMenu( MenuClient ) - -- local MenuClientName = MenuClient:GetName() - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus[MenuClientName] = MENU_CLIENT:New( MenuClient, "Status for Planes" ) - -- MENU_CLIENT_COMMAND:New( MenuClient, "Show Status", MenuStatus[MenuClientName], ShowStatus, MenuClient, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneClient = CLIENT:FindByName( "Plane 1" ) - -- if PlaneClient and PlaneClient:IsAlive() then - -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneClient ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneClient ) - -- end - -- end, {}, 10, 10 ) - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneClient = CLIENT:FindByName( "Plane 2" ) - -- if PlaneClient and PlaneClient:IsAlive() then - -- local MenuManage = MENU_CLIENT:New( PlaneClient, "Manage Menus" ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneClient ) - -- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneClient ) - -- end - -- end, {}, 10, 10 ) - MENU_CLIENT = { - ClassName = "MENU_CLIENT" - } - - --- MENU_CLIENT constructor. Creates a new radio menu item for a client. - -- @param #MENU_CLIENT self - -- @param Wrapper.Client#CLIENT Client The Client owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. - -- @return #MENU_CLIENT self - function MENU_CLIENT:New( Client, MenuText, ParentMenu ) - - -- Arrange meta tables - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, MENU_BASE:New( MenuText, MenuParentPath ) ) - self:F( { Client, MenuText, ParentMenu } ) - - self.MenuClient = Client - self.MenuClientGroupID = Client:GetClientGroupID() - self.MenuParentPath = MenuParentPath - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self.Menus = {} - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - self:T( { Client:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) - - local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText - if MenuPath[MenuPathID] then - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) - end - - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) - MenuPath[MenuPathID] = self.MenuPath - - self:T( { Client:GetClientGroupName(), self.MenuPath } ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - return self - end - - --- Removes the sub menus recursively of this @{#MENU_CLIENT}. - -- @param #MENU_CLIENT self - -- @return #MENU_CLIENT self - function MENU_CLIENT:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the sub menus recursively of this MENU_CLIENT. - -- @param #MENU_CLIENT self - -- @return #nil - function MENU_CLIENT:Remove() - self:F( self.MenuPath ) - - self:RemoveSubMenus() - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then - MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil - end - - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - return nil - end - - - --- The MENU_CLIENT_COMMAND class - -- @type MENU_CLIENT_COMMAND - -- @extends Menu#MENU_COMMAND - MENU_CLIENT_COMMAND = { - ClassName = "MENU_CLIENT_COMMAND" - } - - --- MENU_CLIENT_COMMAND constructor. Creates a new radio command item for a client, which can invoke a function with parameters. - -- @param #MENU_CLIENT_COMMAND self - -- @param Wrapper.Client#CLIENT Client The Client owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #MENU_BASE ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. - -- @return Menu#MENU_CLIENT_COMMAND self - function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, ... ) - - -- Arrange meta tables - - local MenuParentPath = {} - if ParentMenu ~= nil then - MenuParentPath = ParentMenu.MenuPath - end - - local self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, MenuParentPath, CommandMenuFunction, arg ) ) -- Menu#MENU_CLIENT_COMMAND - - self.MenuClient = MenuClient - self.MenuClientGroupID = MenuClient:GetClientGroupID() - self.MenuParentPath = MenuParentPath - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, arg } ) - - local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText - if MenuPath[MenuPathID] then - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) - end - - self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler, arg ) - MenuPath[MenuPathID] = self.MenuPath - - ParentMenu.Menus[self.MenuPath] = self - - return self - end - - --- Removes a menu structure for a client. - -- @param #MENU_CLIENT_COMMAND self - -- @return #nil - function MENU_CLIENT_COMMAND:Remove() - self:F( self.MenuPath ) - - if not _MENUCLIENTS[self.MenuClientGroupID] then - _MENUCLIENTS[self.MenuClientGroupID] = {} - end - - local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] - - if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then - MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil - end - - missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - return nil - end -end - ---- MENU_GROUP - -do - -- This local variable is used to cache the menus registered under groups. - -- Menus don't dissapear when groups for players are destroyed and restarted. - -- So every menu for a client created must be tracked so that program logic accidentally does not create. - -- the same menus twice during initialization logic. - -- These menu classes are handling this logic with this variable. - local _MENUGROUPS = {} - - --- The MENU_GROUP class - -- @type MENU_GROUP - -- @extends Menu#MENU_BASE - -- @usage - -- -- This demo creates a menu structure for the two groups of planes. - -- -- Each group will receive a different menu structure. - -- -- To test, join the planes, then look at the other radio menus (Option F10). - -- -- Then switch planes and check if the menu is still there. - -- -- And play with the Add and Remove menu options. - -- - -- -- Note that in multi player, this will only work after the DCS groups bug is solved. - -- - -- local function ShowStatus( PlaneGroup, StatusText, Coalition ) - -- - -- MESSAGE:New( Coalition, 15 ):ToRed() - -- PlaneGroup:Message( StatusText, 15 ) - -- end - -- - -- local MenuStatus = {} - -- - -- local function RemoveStatusMenu( MenuGroup ) - -- local MenuGroupName = MenuGroup:GetName() - -- MenuStatus[MenuGroupName]:Remove() - -- end - -- - -- --- @param Wrapper.Group#GROUP MenuGroup - -- local function AddStatusMenu( MenuGroup ) - -- local MenuGroupName = MenuGroup:GetName() - -- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object. - -- MenuStatus[MenuGroupName] = MENU_GROUP:New( MenuGroup, "Status for Planes" ) - -- MENU_GROUP_COMMAND:New( MenuGroup, "Show Status", MenuStatus[MenuGroupName], ShowStatus, MenuGroup, "Status of planes is ok!", "Message to Red Coalition" ) - -- end - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneGroup = GROUP:FindByName( "Plane 1" ) - -- if PlaneGroup and PlaneGroup:IsAlive() then - -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 1", MenuManage, AddStatusMenu, PlaneGroup ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 1", MenuManage, RemoveStatusMenu, PlaneGroup ) - -- end - -- end, {}, 10, 10 ) - -- - -- SCHEDULER:New( nil, - -- function() - -- local PlaneGroup = GROUP:FindByName( "Plane 2" ) - -- if PlaneGroup and PlaneGroup:IsAlive() then - -- local MenuManage = MENU_GROUP:New( PlaneGroup, "Manage Menus" ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Add Status Menu Plane 2", MenuManage, AddStatusMenu, PlaneGroup ) - -- MENU_GROUP_COMMAND:New( PlaneGroup, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneGroup ) - -- end - -- end, {}, 10, 10 ) - -- - MENU_GROUP = { - ClassName = "MENU_GROUP" - } - - --- MENU_GROUP constructor. Creates a new radio menu item for a group. - -- @param #MENU_GROUP self - -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. - -- @param #string MenuText The text for the menu. - -- @param #table ParentMenu The parent menu. - -- @return #MENU_GROUP self - function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu ) - - -- Determine if the menu was not already created and already visible at the group. - -- If it is visible, then return the cached self, otherwise, create self and cache it. - - MenuGroup._Menus = MenuGroup._Menus or {} - local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText - if MenuGroup._Menus[Path] then - self = MenuGroup._Menus[Path] - else - self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) - MenuGroup._Menus[Path] = self - - self.Menus = {} - - self.MenuGroup = MenuGroup - self.Path = Path - self.MenuGroupID = MenuGroup:GetID() - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { "Adding Menu ", MenuText, self.MenuParentPath } ) - self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, self.MenuParentPath ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - end - - self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) - - return self - end - - --- Removes the sub menus recursively of this MENU_GROUP. - -- @param #MENU_GROUP self - -- @return #MENU_GROUP self - function MENU_GROUP:RemoveSubMenus() - self:F( self.MenuPath ) - - for MenuID, Menu in pairs( self.Menus ) do - Menu:Remove() - end - - end - - --- Removes the main menu and sub menus recursively of this MENU_GROUP. - -- @param #MENU_GROUP self - -- @return #nil - function MENU_GROUP:Remove() - self:F( { self.MenuGroupID, self.MenuPath } ) - - self:RemoveSubMenus() - - if self.MenuGroup._Menus[self.Path] then - self = self.MenuGroup._Menus[self.Path] - - missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) - if self.ParentMenu then - self.ParentMenu.Menus[self.MenuPath] = nil - end - self:E( self.MenuGroup._Menus[self.Path] ) - self.MenuGroup._Menus[self.Path] = nil - self = nil - end - return nil - end - - - --- The MENU_GROUP_COMMAND class - -- @type MENU_GROUP_COMMAND - -- @extends Menu#MENU_BASE - MENU_GROUP_COMMAND = { - ClassName = "MENU_GROUP_COMMAND" - } - - --- Creates a new radio command item for a group - -- @param #MENU_GROUP_COMMAND self - -- @param Wrapper.Group#GROUP MenuGroup The Group owning the menu. - -- @param MenuText The text for the menu. - -- @param ParentMenu The parent menu. - -- @param CommandMenuFunction A function that is called when the menu key is pressed. - -- @param CommandMenuArgument An argument for the function. - -- @return Menu#MENU_GROUP_COMMAND self - function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, ... ) - - MenuGroup._Menus = MenuGroup._Menus or {} - local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText - if MenuGroup._Menus[Path] then - self = MenuGroup._Menus[Path] - else - self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) ) - MenuGroup._Menus[Path] = self - - self.Path = Path - self.MenuGroup = MenuGroup - self.MenuGroupID = MenuGroup:GetID() - self.MenuText = MenuText - self.ParentMenu = ParentMenu - - self:T( { "Adding Command Menu ", MenuText, self.MenuParentPath } ) - self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler, arg ) - - if ParentMenu and ParentMenu.Menus then - ParentMenu.Menus[self.MenuPath] = self - end - end - - self:F( { MenuGroup:GetName(), MenuText, ParentMenu.MenuPath } ) - - return self - end - - --- Removes a menu structure for a group. - -- @param #MENU_GROUP_COMMAND self - -- @return #nil - function MENU_GROUP_COMMAND:Remove() - self:F( { self.MenuGroupID, self.MenuPath } ) - - if self.MenuGroup._Menus[self.Path] then - self = self.MenuGroup._Menus[self.Path] - - missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath ) - self.ParentMenu.Menus[self.MenuPath] = nil - self:E( self.MenuGroup._Menus[self.Path] ) - self.MenuGroup._Menus[self.Path] = nil - self = nil - end - - return nil - end - -end - ---- This module contains the ZONE classes, inherited from @{Core.Zone#ZONE_BASE}. --- There are essentially two core functions that zones accomodate: --- --- * Test if an object is within the zone boundaries. --- * Provide the zone behaviour. Some zones are static, while others are moveable. --- --- The object classes are using the zone classes to test the zone boundaries, which can take various forms: --- --- * Test if completely within the zone. --- * Test if partly within the zone (for @{Wrapper.Group#GROUP} objects). --- * Test if not in the zone. --- * Distance to the nearest intersecting point of the zone. --- * Distance to the center of the zone. --- * ... --- --- Each of these ZONE classes have a zone name, and specific parameters defining the zone type: --- --- * @{Core.Zone#ZONE_BASE}: The ZONE_BASE class defining the base for all other zone classes. --- * @{Core.Zone#ZONE_RADIUS}: The ZONE_RADIUS class defined by a zone name, a location and a radius. --- * @{Core.Zone#ZONE}: The ZONE class, defined by the zone name as defined within the Mission Editor. --- * @{Core.Zone#ZONE_UNIT}: The ZONE_UNIT class defines by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- * @{Core.Zone#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. --- * @{Core.Zone#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- --- === --- --- 1) @{Core.Zone#ZONE_BASE} class, extends @{Core.Base#BASE} --- ================================================ --- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. --- --- ### 1.1) Each zone has a name: --- --- * @{#ZONE_BASE.GetName}(): Returns the name of the zone. --- --- ### 1.2) Each zone implements two polymorphic functions defined in @{Core.Zone#ZONE_BASE}: --- --- * @{#ZONE_BASE.IsPointVec2InZone}(): Returns if a @{Core.Point#POINT_VEC2} is within the zone. --- * @{#ZONE_BASE.IsPointVec3InZone}(): Returns if a @{Core.Point#POINT_VEC3} is within the zone. --- --- ### 1.3) A zone has a probability factor that can be set to randomize a selection between zones: --- --- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% ) --- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% ) --- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate. --- --- ### 1.4) A zone manages Vectors: --- --- * @{#ZONE_BASE.GetVec2}(): Returns the @{Dcs.DCSTypes#Vec2} coordinate of the zone. --- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- --- ### 1.5) A zone has a bounding square: --- --- * @{#ZONE_BASE.GetBoundingSquare}(): Get the outer most bounding square of the zone. --- --- ### 1.6) A zone can be marked: --- --- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color. --- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color. --- --- === --- --- 2) @{Core.Zone#ZONE_RADIUS} class, extends @{Core.Zone#ZONE_BASE} --- ======================================================= --- The ZONE_RADIUS class defined by a zone name, a location and a radius. --- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties. --- --- ### 2.1) @{Core.Zone#ZONE_RADIUS} constructor: --- --- * @{#ZONE_BASE.New}(): Constructor. --- --- ### 2.2) Manage the radius of the zone: --- --- * @{#ZONE_BASE.SetRadius}(): Sets the radius of the zone. --- * @{#ZONE_BASE.GetRadius}(): Returns the radius of the zone. --- --- ### 2.3) Manage the location of the zone: --- --- * @{#ZONE_BASE.SetVec2}(): Sets the @{Dcs.DCSTypes#Vec2} of the zone. --- * @{#ZONE_BASE.GetVec2}(): Returns the @{Dcs.DCSTypes#Vec2} of the zone. --- * @{#ZONE_BASE.GetVec3}(): Returns the @{Dcs.DCSTypes#Vec3} of the zone, taking an additional height parameter. --- --- === --- --- 3) @{Core.Zone#ZONE} class, extends @{Core.Zone#ZONE_RADIUS} --- ========================================== --- The ZONE class, defined by the zone name as defined within the Mission Editor. --- This class implements the inherited functions from {Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 4) @{Core.Zone#ZONE_UNIT} class, extends @{Core.Zone#ZONE_RADIUS} --- ======================================================= --- The ZONE_UNIT class defined by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 5) @{Core.Zone#ZONE_GROUP} class, extends @{Core.Zone#ZONE_RADIUS} --- ======================================================= --- The ZONE_GROUP class defines by a zone around a @{Wrapper.Group#GROUP} with a radius. The current leader of the group defines the center of the zone. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- === --- --- 6) @{Core.Zone#ZONE_POLYGON_BASE} class, extends @{Core.Zone#ZONE_BASE} --- ======================================================== --- The ZONE_POLYGON_BASE class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- This class is an abstract BASE class for derived classes, and is not meant to be instantiated. --- --- === --- --- 7) @{Core.Zone#ZONE_POLYGON} class, extends @{Core.Zone#ZONE_POLYGON_BASE} --- ================================================================ --- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- This class implements the inherited functions from @{Core.Zone#ZONE_RADIUS} taking into account the own zone format and properties. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-15: ZONE_BASE:**GetName()** added. --- --- 2016-08-15: ZONE_BASE:**SetZoneProbability( ZoneProbability )** added. --- --- 2016-08-15: ZONE_BASE:**GetZoneProbability()** added. --- --- 2016-08-15: ZONE_BASE:**GetZoneMaybe()** added. --- --- === --- --- @module Zone --- @author FlightControl - - ---- The ZONE_BASE class --- @type ZONE_BASE --- @field #string ZoneName Name of the zone. --- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. --- @extends Core.Base#BASE -ZONE_BASE = { - ClassName = "ZONE_BASE", - ZoneName = "", - ZoneProbability = 1, - } - - ---- The ZONE_BASE.BoundingSquare --- @type ZONE_BASE.BoundingSquare --- @field Dcs.DCSTypes#Distance x1 The lower x coordinate (left down) --- @field Dcs.DCSTypes#Distance y1 The lower y coordinate (left down) --- @field Dcs.DCSTypes#Distance x2 The higher x coordinate (right up) --- @field Dcs.DCSTypes#Distance y2 The higher y coordinate (right up) - - ---- ZONE_BASE constructor --- @param #ZONE_BASE self --- @param #string ZoneName Name of the zone. --- @return #ZONE_BASE self -function ZONE_BASE:New( ZoneName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( ZoneName ) - - self.ZoneName = ZoneName - - return self -end - ---- Returns the name of the zone. --- @param #ZONE_BASE self --- @return #string The name of the zone. -function ZONE_BASE:GetName() - self:F2() - - return self.ZoneName -end ---- Returns if a location is within the zone. --- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_BASE:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - return false -end - ---- Returns if a point is within the zone. --- @param #ZONE_BASE self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. --- @return #boolean true if the point is within the zone. -function ZONE_BASE:IsPointVec3InZone( Vec3 ) - self:F2( Vec3 ) - - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) - - return InZone -end - ---- Returns the @{Dcs.DCSTypes#Vec2} coordinate of the zone. --- @param #ZONE_BASE self --- @return #nil. -function ZONE_BASE:GetVec2() - self:F2( self.ZoneName ) - - return nil -end ---- Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- @param #ZONE_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinates. -function ZONE_BASE:GetRandomVec2() - return nil -end - ---- Get the bounding square the zone. --- @param #ZONE_BASE self --- @return #nil The bounding square. -function ZONE_BASE:GetBoundingSquare() - --return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } - return nil -end - - ---- Smokes the zone boundaries in a color. --- @param #ZONE_BASE self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. -function ZONE_BASE:SmokeZone( SmokeColor ) - self:F2( SmokeColor ) - -end - ---- Set the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @param ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability. -function ZONE_BASE:SetZoneProbability( ZoneProbability ) - self:F2( ZoneProbability ) - - self.ZoneProbability = ZoneProbability or 1 - return self -end - ---- Get the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @return #number A value between 0 and 1. 0 = 0% and 1 = 100% probability. -function ZONE_BASE:GetZoneProbability() - self:F2() - - return self.ZoneProbability -end - ---- Get the zone taking into account the randomization probability of a zone to be selected. --- @param #ZONE_BASE self --- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor. --- @return #nil The zone is not selected taking into account the randomization probability factor. -function ZONE_BASE:GetZoneMaybe() - self:F2() - - local Randomization = math.random() - if Randomization <= self.ZoneProbability then - return self - else - return nil - end -end - - ---- The ZONE_RADIUS class, defined by a zone name, a location and a radius. --- @type ZONE_RADIUS --- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone. --- @field Dcs.DCSTypes#Distance Radius The radius of the zone. --- @extends Core.Zone#ZONE_BASE -ZONE_RADIUS = { - ClassName="ZONE_RADIUS", - } - ---- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius. --- @param #ZONE_RADIUS self --- @param #string ZoneName Name of the zone. --- @param Dcs.DCSTypes#Vec2 Vec2 The location of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:New( ZoneName, Vec2, Radius ) - local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) - self:F( { ZoneName, Vec2, Radius } ) - - self.Radius = Radius - self.Vec2 = Vec2 - - return self -end - ---- Smokes the zone boundaries in a color. --- @param #ZONE_RADIUS self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. --- @param #number Points (optional) The amount of points in the circle. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:SmokeZone( SmokeColor, Points ) - self:F2( SmokeColor ) - - local Point = {} - local Vec2 = self:GetVec2() - - Points = Points and Points or 360 - - local Angle - local RadialBase = math.pi*2 - - for Angle = 0, 360, 360 / Points do - local Radial = Angle * RadialBase / 360 - Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() - Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() - POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor ) - end - - return self -end - - ---- Flares the zone boundaries in a color. --- @param #ZONE_RADIUS self --- @param Utilities.Utils#FLARECOLOR FlareColor The flare color. --- @param #number Points (optional) The amount of points in the circle. --- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. --- @return #ZONE_RADIUS self -function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth ) - self:F2( { FlareColor, Azimuth } ) - - local Point = {} - local Vec2 = self:GetVec2() - - Points = Points and Points or 360 - - local Angle - local RadialBase = math.pi*2 - - for Angle = 0, 360, 360 / Points do - local Radial = Angle * RadialBase / 360 - Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius() - Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius() - POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth ) - end - - return self -end - ---- Returns the radius of the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Distance The radius of the zone. -function ZONE_RADIUS:GetRadius() - self:F2( self.ZoneName ) - - self:T2( { self.Radius } ) - - return self.Radius -end - ---- Sets the radius of the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return Dcs.DCSTypes#Distance The radius of the zone. -function ZONE_RADIUS:SetRadius( Radius ) - self:F2( self.ZoneName ) - - self.Radius = Radius - self:T2( { self.Radius } ) - - return self.Radius -end - ---- Returns the @{Dcs.DCSTypes#Vec2} of the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Vec2 The location of the zone. -function ZONE_RADIUS:GetVec2() - self:F2( self.ZoneName ) - - self:T2( { self.Vec2 } ) - - return self.Vec2 -end - ---- Sets the @{Dcs.DCSTypes#Vec2} of the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The new location of the zone. --- @return Dcs.DCSTypes#Vec2 The new location of the zone. -function ZONE_RADIUS:SetVec2( Vec2 ) - self:F2( self.ZoneName ) - - self.Vec2 = Vec2 - - self:T2( { self.Vec2 } ) - - return self.Vec2 -end - ---- Returns the @{Dcs.DCSTypes#Vec3} of the ZONE_RADIUS. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. -function ZONE_RADIUS:GetVec3( Height ) - self:F2( { self.ZoneName, Height } ) - - Height = Height or 0 - local Vec2 = self:GetVec2() - - local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } - - self:T2( { Vec3 } ) - - return Vec3 -end - - ---- Returns if a location is within the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_RADIUS:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - local ZoneVec2 = self:GetVec2() - - if ZoneVec2 then - if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then - return true - end - end - - return false -end - ---- Returns if a point is within the zone. --- @param #ZONE_RADIUS self --- @param Dcs.DCSTypes#Vec3 Vec3 The point to test. --- @return #boolean true if the point is within the zone. -function ZONE_RADIUS:IsPointVec3InZone( Vec3 ) - self:F2( Vec3 ) - - local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } ) - - return InZone -end - ---- Returns a random location within the zone. --- @param #ZONE_RADIUS self --- @return Dcs.DCSTypes#Vec2 The random location within the zone. -function ZONE_RADIUS:GetRandomVec2() - self:F( self.ZoneName ) - - local Point = {} - local Vec2 = self:GetVec2() - - local angle = math.random() * math.pi*2; - Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { Point } ) - - return Point -end - - - ---- The ZONE class, defined by the zone name as defined within the Mission Editor. The location and the radius are automatically collected from the mission settings. --- @type ZONE --- @extends Core.Zone#ZONE_RADIUS -ZONE = { - ClassName="ZONE", - } - - ---- Constructor of ZONE, taking the zone name. --- @param #ZONE self --- @param #string ZoneName The name of the zone as defined within the mission editor. --- @return #ZONE -function ZONE:New( ZoneName ) - - local Zone = trigger.misc.getZone( ZoneName ) - - if not Zone then - error( "Zone " .. ZoneName .. " does not exist." ) - return nil - end - - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, { x = Zone.point.x, y = Zone.point.z }, Zone.radius ) ) - self:F( ZoneName ) - - self.Zone = Zone - - return self -end - - ---- The ZONE_UNIT class defined by a zone around a @{Wrapper.Unit#UNIT} with a radius. --- @type ZONE_UNIT --- @field Wrapper.Unit#UNIT ZoneUNIT --- @extends Core.Zone#ZONE_RADIUS -ZONE_UNIT = { - ClassName="ZONE_UNIT", - } - ---- Constructor to create a ZONE_UNIT instance, taking the zone name, a zone unit and a radius. --- @param #ZONE_UNIT self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Unit#UNIT ZoneUNIT The unit as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_UNIT self -function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius ) - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) ) - self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } ) - - self.ZoneUNIT = ZoneUNIT - self.LastVec2 = ZoneUNIT:GetVec2() - - return self -end - - ---- Returns the current location of the @{Wrapper.Unit#UNIT}. --- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Wrapper.Unit#UNIT}location. -function ZONE_UNIT:GetVec2() - self:F( self.ZoneName ) - - local ZoneVec2 = self.ZoneUNIT:GetVec2() - if ZoneVec2 then - self.LastVec2 = ZoneVec2 - return ZoneVec2 - else - return self.LastVec2 - end - - self:T( { ZoneVec2 } ) - - return nil -end - ---- Returns a random location within the zone. --- @param #ZONE_UNIT self --- @return Dcs.DCSTypes#Vec2 The random location within the zone. -function ZONE_UNIT:GetRandomVec2() - self:F( self.ZoneName ) - - local RandomVec2 = {} - local Vec2 = self.ZoneUNIT:GetVec2() - - if not Vec2 then - Vec2 = self.LastVec2 - end - - local angle = math.random() * math.pi*2; - RandomVec2.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - RandomVec2.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { RandomVec2 } ) - - return RandomVec2 -end - ---- Returns the @{Dcs.DCSTypes#Vec3} of the ZONE_UNIT. --- @param #ZONE_UNIT self --- @param Dcs.DCSTypes#Distance Height The height to add to the land height where the center of the zone is located. --- @return Dcs.DCSTypes#Vec3 The point of the zone. -function ZONE_UNIT:GetVec3( Height ) - self:F2( self.ZoneName ) - - Height = Height or 0 - - local Vec2 = self:GetVec2() - - local Vec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y } - - self:T2( { Vec3 } ) - - return Vec3 -end - ---- The ZONE_GROUP class defined by a zone around a @{Group}, taking the average center point of all the units within the Group, with a radius. --- @type ZONE_GROUP --- @field Wrapper.Group#GROUP ZoneGROUP --- @extends Core.Zone#ZONE_RADIUS -ZONE_GROUP = { - ClassName="ZONE_GROUP", - } - ---- Constructor to create a ZONE_GROUP instance, taking the zone name, a zone @{Wrapper.Group#GROUP} and a radius. --- @param #ZONE_GROUP self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Group#GROUP ZoneGROUP The @{Group} as the center of the zone. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone. --- @return #ZONE_GROUP self -function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius ) - local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) ) - self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } ) - - self.ZoneGROUP = ZoneGROUP - - return self -end - - ---- Returns the current location of the @{Group}. --- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location. -function ZONE_GROUP:GetVec2() - self:F( self.ZoneName ) - - local ZoneVec2 = self.ZoneGROUP:GetVec2() - - self:T( { ZoneVec2 } ) - - return ZoneVec2 -end - ---- Returns a random location within the zone of the @{Group}. --- @param #ZONE_GROUP self --- @return Dcs.DCSTypes#Vec2 The random location of the zone based on the @{Group} location. -function ZONE_GROUP:GetRandomVec2() - self:F( self.ZoneName ) - - local Point = {} - local Vec2 = self.ZoneGROUP:GetVec2() - - local angle = math.random() * math.pi*2; - Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius(); - Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius(); - - self:T( { Point } ) - - return Point -end - - - --- Polygons - ---- The ZONE_POLYGON_BASE class defined by an array of @{Dcs.DCSTypes#Vec2}, forming a polygon. --- @type ZONE_POLYGON_BASE --- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{Dcs.DCSTypes#Vec2}. --- @extends Core.Zone#ZONE_BASE -ZONE_POLYGON_BASE = { - ClassName="ZONE_POLYGON_BASE", - } - ---- A points array. --- @type ZONE_POLYGON_BASE.ListVec2 --- @list - ---- Constructor to create a ZONE_POLYGON_BASE instance, taking the zone name and an array of @{Dcs.DCSTypes#Vec2}, forming a polygon. --- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected. --- @param #ZONE_POLYGON_BASE self --- @param #string ZoneName Name of the zone. --- @param #ZONE_POLYGON_BASE.ListVec2 PointsArray An array of @{Dcs.DCSTypes#Vec2}, forming a polygon.. --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:New( ZoneName, PointsArray ) - local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) - self:F( { ZoneName, PointsArray } ) - - local i = 0 - - self.Polygon = {} - - for i = 1, #PointsArray do - self.Polygon[i] = {} - self.Polygon[i].x = PointsArray[i].x - self.Polygon[i].y = PointsArray[i].y - end - - return self -end - ---- Flush polygon coordinates as a table in DCS.log. --- @param #ZONE_POLYGON_BASE self --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:Flush() - self:F2() - - self:E( { Polygon = self.ZoneName, Coordinates = self.Polygon } ) - - return self -end - - ---- Smokes the zone boundaries in a color. --- @param #ZONE_POLYGON_BASE self --- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. --- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:SmokeZone( SmokeColor ) - self:F2( SmokeColor ) - - local i - local j - local Segments = 10 - - i = 1 - j = #self.Polygon - - while i <= #self.Polygon do - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) - - local DeltaX = self.Polygon[j].x - self.Polygon[i].x - local DeltaY = self.Polygon[j].y - self.Polygon[i].y - - for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. - local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments ) - local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments ) - POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor ) - end - j = i - i = i + 1 - end - - return self -end - - - - ---- Returns if a location is within the zone. --- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html --- @param #ZONE_POLYGON_BASE self --- @param Dcs.DCSTypes#Vec2 Vec2 The location to test. --- @return #boolean true if the location is within the zone. -function ZONE_POLYGON_BASE:IsPointVec2InZone( Vec2 ) - self:F2( Vec2 ) - - local Next - local Prev - local InPolygon = false - - Next = 1 - Prev = #self.Polygon - - while Next <= #self.Polygon do - self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) - if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and - ( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) - ) then - InPolygon = not InPolygon - end - self:T2( { InPolygon = InPolygon } ) - Prev = Next - Next = Next + 1 - end - - self:T( { InPolygon = InPolygon } ) - return InPolygon -end - ---- Define a random @{Dcs.DCSTypes#Vec2} within the zone. --- @param #ZONE_POLYGON_BASE self --- @return Dcs.DCSTypes#Vec2 The Vec2 coordinate. -function ZONE_POLYGON_BASE:GetRandomVec2() - self:F2() - - --- It is a bit tricky to find a random point within a polygon. Right now i am doing it the dirty and inefficient way... - local Vec2Found = false - local Vec2 - local BS = self:GetBoundingSquare() - - self:T2( BS ) - - while Vec2Found == false do - Vec2 = { x = math.random( BS.x1, BS.x2 ), y = math.random( BS.y1, BS.y2 ) } - self:T2( Vec2 ) - if self:IsPointVec2InZone( Vec2 ) then - Vec2Found = true - end - end - - self:T2( Vec2 ) - - return Vec2 -end - ---- Get the bounding square the zone. --- @param #ZONE_POLYGON_BASE self --- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square. -function ZONE_POLYGON_BASE:GetBoundingSquare() - - local x1 = self.Polygon[1].x - local y1 = self.Polygon[1].y - local x2 = self.Polygon[1].x - local y2 = self.Polygon[1].y - - for i = 2, #self.Polygon do - self:T2( { self.Polygon[i], x1, y1, x2, y2 } ) - x1 = ( x1 > self.Polygon[i].x ) and self.Polygon[i].x or x1 - x2 = ( x2 < self.Polygon[i].x ) and self.Polygon[i].x or x2 - y1 = ( y1 > self.Polygon[i].y ) and self.Polygon[i].y or y1 - y2 = ( y2 < self.Polygon[i].y ) and self.Polygon[i].y or y2 - - end - - return { x1 = x1, y1 = y1, x2 = x2, y2 = y2 } -end - - - - - ---- The ZONE_POLYGON class defined by a sequence of @{Wrapper.Group#GROUP} waypoints within the Mission Editor, forming a polygon. --- @type ZONE_POLYGON --- @extends Core.Zone#ZONE_POLYGON_BASE -ZONE_POLYGON = { - ClassName="ZONE_POLYGON", - } - ---- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Wrapper.Group#GROUP} defined within the Mission Editor. --- The @{Wrapper.Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON. --- @param #ZONE_POLYGON self --- @param #string ZoneName Name of the zone. --- @param Wrapper.Group#GROUP ZoneGroup The GROUP waypoints as defined within the Mission Editor define the polygon shape. --- @return #ZONE_POLYGON self -function ZONE_POLYGON:New( ZoneName, ZoneGroup ) - - local GroupPoints = ZoneGroup:GetTaskRoute() - - local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) ) - self:F( { ZoneName, ZoneGroup, self.Polygon } ) - - return self -end - ---- This module contains the DATABASE class, managing the database of mission objects. --- --- ==== --- --- 1) @{Core.Database#DATABASE} class, extends @{Core.Base#BASE} --- =================================================== --- Mission designers can use the DATABASE class to refer to: --- --- * UNITS --- * GROUPS --- * CLIENTS --- * AIRPORTS --- * PLAYERSJOINED --- * PLAYERS --- --- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor. --- --- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE. --- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required. --- --- 1.1) DATABASE iterators --- ----------------------- --- You can iterate the database with the available iterator methods. --- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the DATABASE: --- --- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE. --- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE. --- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE. --- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE. --- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE. --- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE. --- --- === --- --- @module Database --- @author FlightControl - ---- DATABASE class --- @type DATABASE --- @extends Core.Base#BASE -DATABASE = { - ClassName = "DATABASE", - Templates = { - Units = {}, - Groups = {}, - ClientsByName = {}, - ClientsByID = {}, - }, - UNITS = {}, - STATICS = {}, - GROUPS = {}, - PLAYERS = {}, - PLAYERSJOINED = {}, - CLIENTS = {}, - AIRBASES = {}, - NavPoints = {}, -} - -local _DATABASECoalition = - { - [1] = "Red", - [2] = "Blue", - } - -local _DATABASECategory = - { - ["plane"] = Unit.Category.AIRPLANE, - ["helicopter"] = Unit.Category.HELICOPTER, - ["vehicle"] = Unit.Category.GROUND_UNIT, - ["ship"] = Unit.Category.SHIP, - ["static"] = Unit.Category.STRUCTURE, - } - - ---- Creates a new DATABASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #DATABASE self --- @return #DATABASE --- @usage --- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. --- DBObject = DATABASE:New() -function DATABASE:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - _EVENTDISPATCHER:OnBirth( self._EventOnBirth, self ) - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - - - -- Follow alive players and clients - _EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self ) - _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self ) - - self:_RegisterTemplates() - self:_RegisterGroupsAndUnits() - self:_RegisterClients() - self:_RegisterStatics() - self:_RegisterPlayers() - self:_RegisterAirbases() - - return self -end - ---- Finds a Unit based on the Unit Name. --- @param #DATABASE self --- @param #string UnitName --- @return Wrapper.Unit#UNIT The found Unit. -function DATABASE:FindUnit( UnitName ) - - local UnitFound = self.UNITS[UnitName] - return UnitFound -end - - ---- Adds a Unit based on the Unit Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddUnit( DCSUnitName ) - - if not self.UNITS[DCSUnitName] then - local UnitRegister = UNIT:Register( DCSUnitName ) - self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) - end - - return self.UNITS[DCSUnitName] -end - - ---- Deletes a Unit from the DATABASE based on the Unit Name. --- @param #DATABASE self -function DATABASE:DeleteUnit( DCSUnitName ) - - --self.UNITS[DCSUnitName] = nil -end - ---- Adds a Static based on the Static Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddStatic( DCSStaticName ) - - if not self.STATICS[DCSStaticName] then - self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName ) - end -end - - ---- Deletes a Static from the DATABASE based on the Static Name. --- @param #DATABASE self -function DATABASE:DeleteStatic( DCSStaticName ) - - --self.STATICS[DCSStaticName] = nil -end - ---- Finds a STATIC based on the StaticName. --- @param #DATABASE self --- @param #string StaticName --- @return Wrapper.Static#STATIC The found STATIC. -function DATABASE:FindStatic( StaticName ) - - local StaticFound = self.STATICS[StaticName] - return StaticFound -end - ---- Adds a Airbase based on the Airbase Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddAirbase( DCSAirbaseName ) - - if not self.AIRBASES[DCSAirbaseName] then - self.AIRBASES[DCSAirbaseName] = AIRBASE:Register( DCSAirbaseName ) - end -end - - ---- Deletes a Airbase from the DATABASE based on the Airbase Name. --- @param #DATABASE self -function DATABASE:DeleteAirbase( DCSAirbaseName ) - - --self.AIRBASES[DCSAirbaseName] = nil -end - ---- Finds a AIRBASE based on the AirbaseName. --- @param #DATABASE self --- @param #string AirbaseName --- @return Wrapper.Airbase#AIRBASE The found AIRBASE. -function DATABASE:FindAirbase( AirbaseName ) - - local AirbaseFound = self.AIRBASES[AirbaseName] - return AirbaseFound -end - - ---- Finds a CLIENT based on the ClientName. --- @param #DATABASE self --- @param #string ClientName --- @return Wrapper.Client#CLIENT The found CLIENT. -function DATABASE:FindClient( ClientName ) - - local ClientFound = self.CLIENTS[ClientName] - return ClientFound -end - - ---- Adds a CLIENT based on the ClientName in the DATABASE. --- @param #DATABASE self -function DATABASE:AddClient( ClientName ) - - if not self.CLIENTS[ClientName] then - self.CLIENTS[ClientName] = CLIENT:Register( ClientName ) - end - - return self.CLIENTS[ClientName] -end - - ---- Finds a GROUP based on the GroupName. --- @param #DATABASE self --- @param #string GroupName --- @return Wrapper.Group#GROUP The found GROUP. -function DATABASE:FindGroup( GroupName ) - - local GroupFound = self.GROUPS[GroupName] - return GroupFound -end - - ---- Adds a GROUP based on the GroupName in the DATABASE. --- @param #DATABASE self -function DATABASE:AddGroup( GroupName ) - - if not self.GROUPS[GroupName] then - self.GROUPS[GroupName] = GROUP:Register( GroupName ) - end - - return self.GROUPS[GroupName] -end - ---- Adds a player based on the Player Name in the DATABASE. --- @param #DATABASE self -function DATABASE:AddPlayer( UnitName, PlayerName ) - - if PlayerName then - self:E( { "Add player for unit:", UnitName, PlayerName } ) - self.PLAYERS[PlayerName] = self:FindUnit( UnitName ) - self.PLAYERSJOINED[PlayerName] = PlayerName - end -end - ---- Deletes a player from the DATABASE based on the Player Name. --- @param #DATABASE self -function DATABASE:DeletePlayer( PlayerName ) - - if PlayerName then - self:E( { "Clean player:", PlayerName } ) - self.PLAYERS[PlayerName] = nil - end -end - - ---- Instantiate new Groups within the DCSRTE. --- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined: --- SpawnCountryID, SpawnCategoryID --- This method is used by the SPAWN class. --- @param #DATABASE self --- @param #table SpawnTemplate --- @return #DATABASE self -function DATABASE:Spawn( SpawnTemplate ) - self:F( SpawnTemplate.name ) - - self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID } ) - - -- Copy the spawn variables of the template in temporary storage, nullify, and restore the spawn variables. - local SpawnCoalitionID = SpawnTemplate.CoalitionID - local SpawnCountryID = SpawnTemplate.CountryID - local SpawnCategoryID = SpawnTemplate.CategoryID - - -- Nullify - SpawnTemplate.CoalitionID = nil - SpawnTemplate.CountryID = nil - SpawnTemplate.CategoryID = nil - - self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID ) - - self:T3( SpawnTemplate ) - coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) - - -- Restore - SpawnTemplate.CoalitionID = SpawnCoalitionID - SpawnTemplate.CountryID = SpawnCountryID - SpawnTemplate.CategoryID = SpawnCategoryID - - local SpawnGroup = self:AddGroup( SpawnTemplate.name ) - return SpawnGroup -end - ---- Set a status to a Group within the Database, this to check crossing events for example. -function DATABASE:SetStatusGroup( GroupName, Status ) - self:F2( Status ) - - self.Templates.Groups[GroupName].Status = Status -end - ---- Get a status to a Group within the Database, this to check crossing events for example. -function DATABASE:GetStatusGroup( GroupName ) - self:F2( Status ) - - if self.Templates.Groups[GroupName] then - return self.Templates.Groups[GroupName].Status - else - return "" - end -end - ---- Private method that registers new Group Templates within the DATABASE Object. --- @param #DATABASE self --- @param #table GroupTemplate --- @return #DATABASE self -function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID ) - - local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name) - - local TraceTable = {} - - if not self.Templates.Groups[GroupTemplateName] then - self.Templates.Groups[GroupTemplateName] = {} - self.Templates.Groups[GroupTemplateName].Status = nil - end - - -- Delete the spans from the route, it is not needed and takes memory. - if GroupTemplate.route and GroupTemplate.route.spans then - GroupTemplate.route.spans = nil - end - - GroupTemplate.CategoryID = CategoryID - GroupTemplate.CoalitionID = CoalitionID - GroupTemplate.CountryID = CountryID - - self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName - self.Templates.Groups[GroupTemplateName].Template = GroupTemplate - self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId - self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units - self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units - self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID - self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID - self.Templates.Groups[GroupTemplateName].CountryID = CountryID - - - TraceTable[#TraceTable+1] = "Group" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName - - TraceTable[#TraceTable+1] = "Coalition" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID - TraceTable[#TraceTable+1] = "Category" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID - TraceTable[#TraceTable+1] = "Country" - TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID - - TraceTable[#TraceTable+1] = "Units" - - for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do - - UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name) - - self.Templates.Units[UnitTemplate.name] = {} - self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name - self.Templates.Units[UnitTemplate.name].Template = UnitTemplate - self.Templates.Units[UnitTemplate.name].GroupName = GroupTemplateName - self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate - self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId - self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID - self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID - self.Templates.Units[UnitTemplate.name].CountryID = CountryID - - if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then - self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate - self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID - self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID - self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID - self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate - end - - TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName - end - - self:E( TraceTable ) -end - -function DATABASE:GetGroupTemplate( GroupName ) - local GroupTemplate = self.Templates.Groups[GroupName].Template - GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID - GroupTemplate.SpawnCategoryID = self.Templates.Groups[GroupName].CategoryID - GroupTemplate.SpawnCountryID = self.Templates.Groups[GroupName].CountryID - return GroupTemplate -end - -function DATABASE:GetGroupNameFromUnitName( UnitName ) - return self.Templates.Units[UnitName].GroupName -end - -function DATABASE:GetGroupTemplateFromUnitName( UnitName ) - return self.Templates.Units[UnitName].GroupTemplate -end - -function DATABASE:GetCoalitionFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CoalitionID -end - -function DATABASE:GetCategoryFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CategoryID -end - -function DATABASE:GetCountryFromClientTemplate( ClientName ) - return self.Templates.ClientsByName[ClientName].CountryID -end - ---- Airbase - -function DATABASE:GetCoalitionFromAirbase( AirbaseName ) - return self.AIRBASES[AirbaseName]:GetCoalition() -end - -function DATABASE:GetCategoryFromAirbase( AirbaseName ) - return self.AIRBASES[AirbaseName]:GetCategory() -end - - - ---- Private method that registers all alive players in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterPlayers() - - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for UnitId, UnitData in pairs( CoalitionData ) do - self:T3( { "UnitData:", UnitData } ) - if UnitData and UnitData:isExist() then - local UnitName = UnitData:getName() - local PlayerName = UnitData:getPlayerName() - if not self.PLAYERS[PlayerName] then - self:E( { "Add player for unit:", UnitName, PlayerName } ) - self:AddPlayer( UnitName, PlayerName ) - end - end - end - end - - return self -end - - ---- Private method that registers all Groups and Units within in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterGroupsAndUnits() - - local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSGroupId, DCSGroup in pairs( CoalitionData ) do - - if DCSGroup:isExist() then - local DCSGroupName = DCSGroup:getName() - - self:E( { "Register Group:", DCSGroupName } ) - self:AddGroup( DCSGroupName ) - - for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do - - local DCSUnitName = DCSUnit:getName() - self:E( { "Register Unit:", DCSUnitName } ) - self:AddUnit( DCSUnitName ) - end - else - self:E( { "Group does not exist: ", DCSGroup } ) - end - - end - end - - return self -end - ---- Private method that registers all Units of skill Client or Player within in the mission. --- @param #DATABASE self --- @return #DATABASE self -function DATABASE:_RegisterClients() - - for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do - self:E( { "Register Client:", ClientName } ) - self:AddClient( ClientName ) - end - - return self -end - ---- @param #DATABASE self -function DATABASE:_RegisterStatics() - - local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSStaticId, DCSStatic in pairs( CoalitionData ) do - - if DCSStatic:isExist() then - local DCSStaticName = DCSStatic:getName() - - self:E( { "Register Static:", DCSStaticName } ) - self:AddStatic( DCSStaticName ) - else - self:E( { "Static does not exist: ", DCSStatic } ) - end - end - end - - return self -end - ---- @param #DATABASE self -function DATABASE:_RegisterAirbases() - - local CoalitionsData = { AirbasesRed = coalition.getAirbases( coalition.side.RED ), AirbasesBlue = coalition.getAirbases( coalition.side.BLUE ), AirbasesNeutral = coalition.getAirbases( coalition.side.NEUTRAL ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - for DCSAirbaseId, DCSAirbase in pairs( CoalitionData ) do - - local DCSAirbaseName = DCSAirbase:getName() - - self:E( { "Register Airbase:", DCSAirbaseName } ) - self:AddAirbase( DCSAirbaseName ) - end - end - - return self -end - - ---- Events - ---- Handles the OnBirth event for the alive units set. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnBirth( Event ) - self:F2( { Event } ) - - if Event.IniDCSUnit then - self:AddUnit( Event.IniDCSUnitName ) - self:AddGroup( Event.IniDCSGroupName ) - self:_EventOnPlayerEnterUnit( Event ) - end -end - - ---- Handles the OnDead or OnCrash event for alive units set. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnDeadOrCrash( Event ) - self:F2( { Event } ) - - if Event.IniDCSUnit then - if self.UNITS[Event.IniDCSUnitName] then - self:DeleteUnit( Event.IniDCSUnitName ) - -- add logic to correctly remove a group once all units are destroyed... - end - end -end - - ---- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnPlayerEnterUnit( Event ) - self:F2( { Event } ) - - if Event.IniUnit then - local PlayerName = Event.IniUnit:GetPlayerName() - if not self.PLAYERS[PlayerName] then - self:AddPlayer( Event.IniUnitName, PlayerName ) - end - end -end - - ---- Handles the OnPlayerLeaveUnit event to clean the active players table. --- @param #DATABASE self --- @param Core.Event#EVENTDATA Event -function DATABASE:_EventOnPlayerLeaveUnit( Event ) - self:F2( { Event } ) - - if Event.IniUnit then - local PlayerName = Event.IniUnit:GetPlayerName() - if self.PLAYERS[PlayerName] then - self:DeletePlayer( PlayerName ) - end - end -end - ---- Iterators - ---- Iterate the DATABASE and call an iterator function for the given set, providing the Object for each element within the set and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive player in the database. --- @return #DATABASE self -function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set ) - self:F2( arg ) - - local function CoRoutine() - local Count = 0 - for ObjectID, Object in pairs( Set ) do - self:T2( Object ) - IteratorFunction( Object, unpack( arg ) ) - Count = Count + 1 --- if Count % 100 == 0 then --- coroutine.yield( false ) --- end - end - return true - end - --- local co = coroutine.create( CoRoutine ) - local co = CoRoutine - - local function Schedule() - --- local status, res = coroutine.resume( co ) - local status, res = co() - self:T3( { status, res } ) - - if status == false then - error( res ) - end - if res == false then - return true -- resume next time the loop - end - if FinalizeFunction then - FinalizeFunction( unpack( arg ) ) - end - return false - end - - local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter. --- @return #DATABASE self -function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS ) - - return self -end - ---- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter. --- @return #DATABASE self -function DATABASE:ForEachGroup( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.GROUPS ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an player in the database. The function needs to accept the player name. --- @return #DATABASE self -function DATABASE:ForEachPlayer( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.PLAYERS ) - - return self -end - - ---- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter. --- @return #DATABASE self -function DATABASE:ForEachPlayerJoined( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.PLAYERSJOINED ) - - return self -end - ---- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter. --- @return #DATABASE self -function DATABASE:ForEachClient( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.CLIENTS ) - - return self -end - - -function DATABASE:_RegisterTemplates() - self:F2() - - self.Navpoints = {} - self.UNITS = {} - --Build routines.db.units and self.Navpoints - for CoalitionName, coa_data in pairs(env.mission.coalition) do - - if (CoalitionName == 'red' or CoalitionName == 'blue') and type(coa_data) == 'table' then - --self.Units[coa_name] = {} - - ---------------------------------------------- - -- build nav points DB - self.Navpoints[CoalitionName] = {} - if coa_data.nav_points then --navpoints - for nav_ind, nav_data in pairs(coa_data.nav_points) do - - if type(nav_data) == 'table' then - self.Navpoints[CoalitionName][nav_ind] = routines.utils.deepCopy(nav_data) - - self.Navpoints[CoalitionName][nav_ind]['name'] = nav_data.callsignStr -- name is a little bit more self-explanatory. - self.Navpoints[CoalitionName][nav_ind]['point'] = {} -- point is used by SSE, support it. - self.Navpoints[CoalitionName][nav_ind]['point']['x'] = nav_data.x - self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0 - self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y - end - end - end - ------------------------------------------------- - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - - local CountryName = string.upper(cntry_data.name) - --self.Units[coa_name][countryName] = {} - --self.Units[coa_name][countryName]["countryId"] = cntry_data.id - - if type(cntry_data) == 'table' then --just making sure - - for obj_type_name, obj_type_data in pairs(cntry_data) do - - if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then --should be an unncessary check - - local CategoryName = obj_type_name - - if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's a group! - - --self.Units[coa_name][countryName][category] = {} - - for group_num, GroupTemplate in pairs(obj_type_data.group) do - - if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group - self:_RegisterTemplate( - GroupTemplate, - coalition.side[string.upper(CoalitionName)], - _DATABASECategory[string.lower(CategoryName)], - country.id[string.upper(CountryName)] - ) - end --if GroupTemplate and GroupTemplate.units then - end --for group_num, GroupTemplate in pairs(obj_type_data.group) do - end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then - end --if obj_type_name == "helicopter" or obj_type_name == "ship" or obj_type_name == "plane" or obj_type_name == "vehicle" or obj_type_name == "static" then - end --for obj_type_name, obj_type_data in pairs(cntry_data) do - end --if type(cntry_data) == 'table' then - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - - return self -end - - - - ---- This module contains the SET classes. --- --- === --- --- 1) @{Core.Set#SET_BASE} class, extends @{Core.Base#BASE} --- ============================================== --- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. --- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. --- In this way, large loops can be done while not blocking the simulator main processing loop. --- The default **"yield interval"** is after 10 objects processed. --- The default **"time interval"** is after 0.001 seconds. --- --- 1.1) Add or remove objects from the SET --- --------------------------------------- --- Some key core functions are @{Core.Set#SET_BASE.Add} and @{Core.Set#SET_BASE.Remove} to add or remove objects from the SET in your logic. --- --- 1.2) Define the SET iterator **"yield interval"** and the **"time interval"** --- ----------------------------------------------------------------------------- --- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetInteratorIntervals} method. --- You can set the **"yield interval"**, and the **"time interval"**. (See above). --- --- === --- --- 2) @{Core.Set#SET_GROUP} class, extends @{Core.Set#SET_BASE} --- ================================================== --- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Starting with certain prefix strings. --- --- 2.1) SET_GROUP construction method: --- ----------------------------------- --- Create a new SET_GROUP object with the @{#SET_GROUP.New} method: --- --- * @{#SET_GROUP.New}: Creates a new SET_GROUP object. --- --- 2.2) Add or Remove GROUP(s) from SET_GROUP: --- ------------------------------------------- --- GROUPS can be added and removed using the @{Core.Set#SET_GROUP.AddGroupsByName} and @{Core.Set#SET_GROUP.RemoveGroupsByName} respectively. --- These methods take a single GROUP name or an array of GROUP names to be added or removed from SET_GROUP. --- --- 2.3) SET_GROUP filter criteria: --- ------------------------------- --- You can set filter criteria to define the set of groups within the SET_GROUP. --- Filter criteria are defined by: --- --- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s). --- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies). --- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies). --- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: --- --- * @{#SET_GROUP.FilterStart}: Starts the filtering of the groups within the SET_GROUP and add or remove GROUP objects **dynamically**. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. --- --- 2.4) SET_GROUP iterators: --- ------------------------- --- Once the filters have been defined and the SET_GROUP has been built, you can iterate the SET_GROUP with the available iterator methods. --- The iterator methods will walk the SET_GROUP set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_GROUP: --- --- * @{#SET_GROUP.ForEachGroup}: Calls a function for each alive group it finds within the SET_GROUP. --- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupPartlyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- --- ==== --- --- 3) @{Core.Set#SET_UNIT} class, extends @{Core.Set#SET_BASE} --- =================================================== --- Mission designers can use the @{Core.Set#SET_UNIT} class to build sets of units belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Unit types --- * Starting with certain prefix strings. --- --- 3.1) SET_UNIT construction method: --- ---------------------------------- --- Create a new SET_UNIT object with the @{#SET_UNIT.New} method: --- --- * @{#SET_UNIT.New}: Creates a new SET_UNIT object. --- --- 3.2) Add or Remove UNIT(s) from SET_UNIT: --- ----------------------------------------- --- UNITs can be added and removed using the @{Core.Set#SET_UNIT.AddUnitsByName} and @{Core.Set#SET_UNIT.RemoveUnitsByName} respectively. --- These methods take a single UNIT name or an array of UNIT names to be added or removed from SET_UNIT. --- --- 3.3) SET_UNIT filter criteria: --- ------------------------------ --- You can set filter criteria to define the set of units within the SET_UNIT. --- Filter criteria are defined by: --- --- * @{#SET_UNIT.FilterCoalitions}: Builds the SET_UNIT with the units belonging to the coalition(s). --- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). --- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). --- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). --- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: --- --- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units within the SET_UNIT. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. --- --- 3.4) SET_UNIT iterators: --- ------------------------ --- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. --- The iterator methods will walk the SET_UNIT set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_UNIT: --- --- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. --- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- --- Planned iterators methods in development are (so these are not yet available): --- --- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. --- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- --- === --- --- 4) @{Core.Set#SET_CLIENT} class, extends @{Core.Set#SET_BASE} --- =================================================== --- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: --- --- * Coalitions --- * Categories --- * Countries --- * Client types --- * Starting with certain prefix strings. --- --- 4.1) SET_CLIENT construction method: --- ---------------------------------- --- Create a new SET_CLIENT object with the @{#SET_CLIENT.New} method: --- --- * @{#SET_CLIENT.New}: Creates a new SET_CLIENT object. --- --- 4.2) Add or Remove CLIENT(s) from SET_CLIENT: --- ----------------------------------------- --- CLIENTs can be added and removed using the @{Core.Set#SET_CLIENT.AddClientsByName} and @{Core.Set#SET_CLIENT.RemoveClientsByName} respectively. --- These methods take a single CLIENT name or an array of CLIENT names to be added or removed from SET_CLIENT. --- --- 4.3) SET_CLIENT filter criteria: --- ------------------------------ --- You can set filter criteria to define the set of clients within the SET_CLIENT. --- Filter criteria are defined by: --- --- * @{#SET_CLIENT.FilterCoalitions}: Builds the SET_CLIENT with the clients belonging to the coalition(s). --- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies). --- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s). --- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). --- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s). --- --- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: --- --- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients within the SET_CLIENT. --- --- Planned filter criteria within development are (so these are not yet available): --- --- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. --- --- 4.4) SET_CLIENT iterators: --- ------------------------ --- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. --- The iterator methods will walk the SET_CLIENT set, and call for each element within the set a function that you provide. --- The following iterator methods are currently available within the SET_CLIENT: --- --- * @{#SET_CLIENT.ForEachClient}: Calls a function for each alive client it finds within the SET_CLIENT. --- --- ==== --- --- 5) @{Core.Set#SET_AIRBASE} class, extends @{Core.Set#SET_BASE} --- ==================================================== --- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: --- --- * Coalitions --- --- 5.1) SET_AIRBASE construction --- ----------------------------- --- Create a new SET_AIRBASE object with the @{#SET_AIRBASE.New} method: --- --- * @{#SET_AIRBASE.New}: Creates a new SET_AIRBASE object. --- --- 5.2) Add or Remove AIRBASEs from SET_AIRBASE --- -------------------------------------------- --- AIRBASEs can be added and removed using the @{Core.Set#SET_AIRBASE.AddAirbasesByName} and @{Core.Set#SET_AIRBASE.RemoveAirbasesByName} respectively. --- These methods take a single AIRBASE name or an array of AIRBASE names to be added or removed from SET_AIRBASE. --- --- 5.3) SET_AIRBASE filter criteria --- -------------------------------- --- You can set filter criteria to define the set of clients within the SET_AIRBASE. --- Filter criteria are defined by: --- --- * @{#SET_AIRBASE.FilterCoalitions}: Builds the SET_AIRBASE with the airbases belonging to the coalition(s). --- --- Once the filter criteria have been set for the SET_AIRBASE, you can start filtering using: --- --- * @{#SET_AIRBASE.FilterStart}: Starts the filtering of the airbases within the SET_AIRBASE. --- --- 5.4) SET_AIRBASE iterators: --- --------------------------- --- Once the filters have been defined and the SET_AIRBASE has been built, you can iterate the SET_AIRBASE with the available iterator methods. --- The iterator methods will walk the SET_AIRBASE set, and call for each airbase within the set a function that you provide. --- The following iterator methods are currently available within the SET_AIRBASE: --- --- * @{#SET_AIRBASE.ForEachAirbase}: Calls a function for each airbase it finds within the SET_AIRBASE. --- --- ==== --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Contributions: --- --- --- @module Set - - ---- SET_BASE class --- @type SET_BASE --- @field #table Filter --- @field #table Set --- @field #table List --- @field Core.Scheduler#SCHEDULER CallScheduler --- @extends Core.Base#BASE -SET_BASE = { - ClassName = "SET_BASE", - Filter = {}, - Set = {}, - List = {}, -} - ---- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_BASE self --- @return #SET_BASE --- @usage --- -- Define a new SET_BASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE. --- DBObject = SET_BASE:New() -function SET_BASE:New( Database ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE - - self.Database = Database - - self.YieldInterval = 10 - self.TimeInterval = 0.001 - - self.List = {} - self.List.__index = self.List - self.List = setmetatable( { Count = 0 }, self.List ) - - self.CallScheduler = SCHEDULER:New( self ) - - return self -end - ---- Finds an @{Core.Base#BASE} object based on the object Name. --- @param #SET_BASE self --- @param #string ObjectName --- @return Core.Base#BASE The Object found. -function SET_BASE:_Find( ObjectName ) - - local ObjectFound = self.Set[ObjectName] - return ObjectFound -end - - ---- Gets the Set. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:GetSet() - self:F2() - - return self.Set -end - ---- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index. --- @param #SET_BASE self --- @param #string ObjectName --- @param Core.Base#BASE Object --- @return Core.Base#BASE The added BASE Object. -function SET_BASE:Add( ObjectName, Object ) - self:F2( ObjectName ) - - local t = { _ = Object } - - if self.List.last then - self.List.last._next = t - t._prev = self.List.last - self.List.last = t - else - -- this is the first node - self.List.first = t - self.List.last = t - end - - self.List.Count = self.List.Count + 1 - - self.Set[ObjectName] = t._ - -end - ---- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index. --- @param #SET_BASE self --- @param Wrapper.Object#OBJECT Object --- @return Core.Base#BASE The added BASE Object. -function SET_BASE:AddObject( Object ) - self:F2( Object.ObjectName ) - - self:T( Object.UnitName ) - self:T( Object.ObjectName ) - self:Add( Object.ObjectName, Object ) - -end - - - ---- Removes a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. --- @param #SET_BASE self --- @param #string ObjectName -function SET_BASE:Remove( ObjectName ) - self:F( ObjectName ) - - local t = self.Set[ObjectName] - - self:E( { ObjectName, t } ) - - if t then - if t._next then - if t._prev then - t._next._prev = t._prev - t._prev._next = t._next - else - -- this was the first node - t._next._prev = nil - self.List._first = t._next - end - elseif t._prev then - -- this was the last node - t._prev._next = nil - self.List._last = t._prev - else - -- this was the only node - self.List._first = nil - self.List._last = nil - end - - t._next = nil - t._prev = nil - self.List.Count = self.List.Count - 1 - - self.Set[ObjectName] = nil - end - -end - ---- Gets a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name. --- @param #SET_BASE self --- @param #string ObjectName --- @return Core.Base#BASE -function SET_BASE:Get( ObjectName ) - self:F( ObjectName ) - - local t = self.Set[ObjectName] - - self:T3( { ObjectName, t } ) - - return t - -end - ---- Retrieves the amount of objects in the @{Core.Set#SET_BASE} and derived classes. --- @param #SET_BASE self --- @return #number Count -function SET_BASE:Count() - - return self.List.Count -end - - - ---- Copies the Filter criteria from a given Set (for rebuilding a new Set based on an existing Set). --- @param #SET_BASE self --- @param #SET_BASE BaseSet --- @return #SET_BASE -function SET_BASE:SetDatabase( BaseSet ) - - -- Copy the filter criteria of the BaseSet - local OtherFilter = routines.utils.deepCopy( BaseSet.Filter ) - self.Filter = OtherFilter - - -- Now base the new Set on the BaseSet - self.Database = BaseSet:GetSet() - return self -end - - - ---- Define the SET iterator **"yield interval"** and the **"time interval"**. --- @param #SET_BASE self --- @param #number YieldInterval Sets the frequency when the iterator loop will yield after the number of objects processed. The default frequency is 10 objects processed. --- @param #number TimeInterval Sets the time in seconds when the main logic will resume the iterator loop. The default time is 0.001 seconds. --- @return #SET_BASE self -function SET_BASE:SetIteratorIntervals( YieldInterval, TimeInterval ) - - self.YieldInterval = YieldInterval - self.TimeInterval = TimeInterval - - return self -end - - ---- Filters for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:FilterOnce() - - for ObjectName, Object in pairs( self.Database ) do - - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - end - end - - return self -end - ---- Starts the filtering for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:_FilterStart() - - for ObjectName, Object in pairs( self.Database ) do - - if self:IsIncludeObject( Object ) then - self:E( { "Adding Object:", ObjectName } ) - self:Add( ObjectName, Object ) - end - end - - _EVENTDISPATCHER:OnBirth( self._EventOnBirth, self ) - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - - -- Follow alive players and clients - _EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self ) - _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self ) - - - return self -end - ---- Stops the filtering for the defined collection. --- @param #SET_BASE self --- @return #SET_BASE self -function SET_BASE:FilterStop() - - _EVENTDISPATCHER:OnBirthRemove( self ) - _EVENTDISPATCHER:OnDeadRemove( self ) - _EVENTDISPATCHER:OnCrashRemove( self ) - - return self -end - ---- Iterate the SET_BASE while identifying the nearest object from a @{Core.Point#POINT_VEC2}. --- @param #SET_BASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set. --- @return Core.Base#BASE The closest object. -function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 ) - self:F2( PointVec2 ) - - local NearestObject = nil - local ClosestDistance = nil - - for ObjectID, ObjectData in pairs( self.Set ) do - if NearestObject == nil then - NearestObject = ObjectData - ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) - else - local Distance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() ) - if Distance < ClosestDistance then - NearestObject = ObjectData - ClosestDistance = Distance - end - end - end - - return NearestObject -end - - - ------ Private method that registers all alive players in the mission. ----- @param #SET_BASE self ----- @return #SET_BASE self ---function SET_BASE:_RegisterPlayers() --- --- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } --- for CoalitionId, CoalitionData in pairs( CoalitionsData ) do --- for UnitId, UnitData in pairs( CoalitionData ) do --- self:T3( { "UnitData:", UnitData } ) --- if UnitData and UnitData:isExist() then --- local UnitName = UnitData:getName() --- if not self.PlayersAlive[UnitName] then --- self:E( { "Add player for unit:", UnitName, UnitData:getPlayerName() } ) --- self.PlayersAlive[UnitName] = UnitData:getPlayerName() --- end --- end --- end --- end --- --- return self ---end - ---- Events - ---- Handles the OnBirth event for the Set. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnBirth( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:AddInDatabase( Event ) - self:T3( ObjectName, Object ) - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - --self:_EventOnPlayerEnterUnit( Event ) - end - end -end - ---- Handles the OnDead or OnCrash event for alive units set. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:FindInDatabase( Event ) - if ObjectName and Object ~= nil then - self:Remove( ObjectName ) - end - end -end - ---- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied). --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnPlayerEnterUnit( Event ) - self:F3( { Event } ) - - if Event.IniDCSUnit then - local ObjectName, Object = self:AddInDatabase( Event ) - self:T3( ObjectName, Object ) - if self:IsIncludeObject( Object ) then - self:Add( ObjectName, Object ) - --self:_EventOnPlayerEnterUnit( Event ) - end - end -end - ---- Handles the OnPlayerLeaveUnit event to clean the active players table. --- @param #SET_BASE self --- @param Core.Event#EVENTDATA Event -function SET_BASE:_EventOnPlayerLeaveUnit( Event ) - self:F3( { Event } ) - - local ObjectName = Event.IniDCSUnit - if Event.IniDCSUnit then - if Event.IniDCSGroup then - local GroupUnits = Event.IniDCSGroup:getUnits() - local PlayerCount = 0 - for _, DCSUnit in pairs( GroupUnits ) do - if DCSUnit ~= Event.IniDCSUnit then - if DCSUnit:getPlayer() ~= nil then - PlayerCount = PlayerCount + 1 - end - end - end - self:E(PlayerCount) - if PlayerCount == 0 then - self:Remove( Event.IniDCSGroupName ) - end - end - end -end - --- Iterators - ---- Iterate the SET_BASE and derived classes and call an iterator function for the given SET_BASE, providing the Object for each element within the set and optional parameters. --- @param #SET_BASE self --- @param #function IteratorFunction The function that will be called. --- @return #SET_BASE self -function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArguments ) - self:F3( arg ) - - Set = Set or self:GetSet() - arg = arg or {} - - local function CoRoutine() - local Count = 0 - for ObjectID, ObjectData in pairs( Set ) do - local Object = ObjectData - self:T3( Object ) - if Function then - if Function( unpack( FunctionArguments ), Object ) == true then - IteratorFunction( Object, unpack( arg ) ) - end - else - IteratorFunction( Object, unpack( arg ) ) - end - Count = Count + 1 --- if Count % self.YieldInterval == 0 then --- coroutine.yield( false ) --- end - end - return true - end - --- local co = coroutine.create( CoRoutine ) - local co = CoRoutine - - local function Schedule() - --- local status, res = coroutine.resume( co ) - local status, res = co() - self:T3( { status, res } ) - - if status == false then - error( res ) - end - if res == false then - return true -- resume next time the loop - end - - return false - end - - self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) - - return self -end - - ------ Iterate the SET_BASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.DCSUnitsAlive ) --- --- return self ---end --- ------ Iterate the SET_BASE and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachPlayer( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_BASE and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_BASE self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. ----- @return #SET_BASE self ---function SET_BASE:ForEachClient( IteratorFunction, ... ) --- self:F3( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- Decides whether to include the Object --- @param #SET_BASE self --- @param #table Object --- @return #SET_BASE self -function SET_BASE:IsIncludeObject( Object ) - self:F3( Object ) - - return true -end - ---- Flushes the current SET_BASE contents in the log ... (for debugging reasons). --- @param #SET_BASE self --- @return #string A string with the names of the objects. -function SET_BASE:Flush() - self:F3() - - local ObjectNames = "" - for ObjectName, Object in pairs( self.Set ) do - ObjectNames = ObjectNames .. ObjectName .. ", " - end - self:E( { "Objects in Set:", ObjectNames } ) - - return ObjectNames -end - --- SET_GROUP - ---- SET_GROUP class --- @type SET_GROUP --- @extends #SET_BASE -SET_GROUP = { - ClassName = "SET_GROUP", - Filter = { - Coalitions = nil, - Categories = nil, - Countries = nil, - GroupPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Group.Category.AIRPLANE, - helicopter = Group.Category.HELICOPTER, - ground = Group.Category.GROUND_UNIT, - ship = Group.Category.SHIP, - structure = Group.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_GROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_GROUP self --- @return #SET_GROUP --- @usage --- -- Define a new SET_GROUP Object. This DBObject will contain a reference to all alive GROUPS. --- DBObject = SET_GROUP:New() -function SET_GROUP:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) - - return self -end - ---- Add GROUP(s) to SET_GROUP. --- @param Core.Set#SET_GROUP self --- @param #string AddGroupNames A single name or an array of GROUP names. --- @return self -function SET_GROUP:AddGroupsByName( AddGroupNames ) - - local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames } - - for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do - self:Add( AddGroupName, GROUP:FindByName( AddGroupName ) ) - end - - return self -end - ---- Remove GROUP(s) from SET_GROUP. --- @param Core.Set#SET_GROUP self --- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names. --- @return self -function SET_GROUP:RemoveGroupsByName( RemoveGroupNames ) - - local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames } - - for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do - self:Remove( RemoveGroupName.GroupName ) - end - - return self -end - - - - ---- Finds a Group based on the Group Name. --- @param #SET_GROUP self --- @param #string GroupName --- @return Wrapper.Group#GROUP The found Group. -function SET_GROUP:FindGroup( GroupName ) - - local GroupFound = self.Set[GroupName] - return GroupFound -end - - - ---- Builds a set of groups of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_GROUP self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_GROUP self -function SET_GROUP:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of groups out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_GROUP self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_GROUP self -function SET_GROUP:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - ---- Builds a set of groups of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_GROUP self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_GROUP self -function SET_GROUP:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of groups of defined GROUP prefixes. --- All the groups starting with the given prefixes will be included within the set. --- @param #SET_GROUP self --- @param #string Prefixes The prefix of which the group name starts with. --- @return #SET_GROUP self -function SET_GROUP:FilterPrefixes( Prefixes ) - if not self.Filter.GroupPrefixes then - self.Filter.GroupPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.GroupPrefixes[Prefix] = Prefix - end - return self -end - - ---- Starts the filtering. --- @param #SET_GROUP self --- @return #SET_GROUP self -function SET_GROUP:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_GROUP self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the GROUP --- @return #table The GROUP -function SET_GROUP:AddInDatabase( Event ) - self:F3( { Event } ) - - if not self.Database[Event.IniDCSGroupName] then - self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName ) - self:T3( self.Database[Event.IniDCSGroupName] ) - end - - return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_GROUP self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the GROUP --- @return #table The GROUP -function SET_GROUP:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters. --- @param #SET_GROUP self --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroup( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupCompletelyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsCompletelyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence partly in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupPartlyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsPartlyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. --- @param #SET_GROUP self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the SET_GROUP. The function needs to accept a GROUP parameter. --- @return #SET_GROUP self -function SET_GROUP:ForEachGroupNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Group#GROUP GroupObject - function( ZoneObject, GroupObject ) - if GroupObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - - ------ Iterate the SET_GROUP and call an interator function for each **alive** player, providing the Group of the player and optional parameters. ----- @param #SET_GROUP self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. ----- @return #SET_GROUP self ---function SET_GROUP:ForEachPlayer( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_GROUP and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_GROUP self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. ----- @return #SET_GROUP self ---function SET_GROUP:ForEachClient( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- --- @param #SET_GROUP self --- @param Wrapper.Group#GROUP MooseGroup --- @return #SET_GROUP self -function SET_GROUP:IsIncludeObject( MooseGroup ) - self:F2( MooseGroup ) - local MooseGroupInclude = true - - if self.Filter.Coalitions then - local MooseGroupCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MooseGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MooseGroup:GetCoalition() then - MooseGroupCoalition = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCoalition - end - - if self.Filter.Categories then - local MooseGroupCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MooseGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MooseGroup:GetCategory() then - MooseGroupCategory = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCategory - end - - if self.Filter.Countries then - local MooseGroupCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MooseGroup:GetCountry(), CountryName } ) - if country.id[CountryName] == MooseGroup:GetCountry() then - MooseGroupCountry = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupCountry - end - - if self.Filter.GroupPrefixes then - local MooseGroupPrefix = false - for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do - self:T3( { "Prefix:", string.find( MooseGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) - if string.find( MooseGroup:GetName(), GroupPrefix, 1 ) then - MooseGroupPrefix = true - end - end - MooseGroupInclude = MooseGroupInclude and MooseGroupPrefix - end - - self:T2( MooseGroupInclude ) - return MooseGroupInclude -end - ---- SET_UNIT class --- @type SET_UNIT --- @extends Core.Set#SET_BASE -SET_UNIT = { - ClassName = "SET_UNIT", - Units = {}, - Filter = { - Coalitions = nil, - Categories = nil, - Types = nil, - Countries = nil, - UnitPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Unit.Category.AIRPLANE, - helicopter = Unit.Category.HELICOPTER, - ground = Unit.Category.GROUND_UNIT, - ship = Unit.Category.SHIP, - structure = Unit.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_UNIT self --- @return #SET_UNIT --- @usage --- -- Define a new SET_UNIT Object. This DBObject will contain a reference to all alive Units. --- DBObject = SET_UNIT:New() -function SET_UNIT:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) ) - - return self -end - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnit A single UNIT. --- @return #SET_UNIT self -function SET_UNIT:AddUnit( AddUnit ) - self:F2( AddUnit:GetName() ) - - self:Add( AddUnit:GetName(), AddUnit ) - - return self -end - - ---- Add UNIT(s) to SET_UNIT. --- @param #SET_UNIT self --- @param #string AddUnitNames A single name or an array of UNIT names. --- @return #SET_UNIT self -function SET_UNIT:AddUnitsByName( AddUnitNames ) - - local AddUnitNamesArray = ( type( AddUnitNames ) == "table" ) and AddUnitNames or { AddUnitNames } - - self:T( AddUnitNamesArray ) - for AddUnitID, AddUnitName in pairs( AddUnitNamesArray ) do - self:Add( AddUnitName, UNIT:FindByName( AddUnitName ) ) - end - - return self -end - ---- Remove UNIT(s) from SET_UNIT. --- @param Core.Set#SET_UNIT self --- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names. --- @return self -function SET_UNIT:RemoveUnitsByName( RemoveUnitNames ) - - local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames } - - for RemoveUnitID, RemoveUnitName in pairs( RemoveUnitNamesArray ) do - self:Remove( RemoveUnitName ) - end - - return self -end - - ---- Finds a Unit based on the Unit Name. --- @param #SET_UNIT self --- @param #string UnitName --- @return Wrapper.Unit#UNIT The found Unit. -function SET_UNIT:FindUnit( UnitName ) - - local UnitFound = self.Set[UnitName] - return UnitFound -end - - - ---- Builds a set of units of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_UNIT self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_UNIT self -function SET_UNIT:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of units out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_UNIT self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_UNIT self -function SET_UNIT:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - - ---- Builds a set of units of defined unit types. --- Possible current types are those types known within DCS world. --- @param #SET_UNIT self --- @param #string Types Can take those type strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterTypes( Types ) - if not self.Filter.Types then - self.Filter.Types = {} - end - if type( Types ) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs( Types ) do - self.Filter.Types[Type] = Type - end - return self -end - - ---- Builds a set of units of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_UNIT self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_UNIT self -function SET_UNIT:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of units of defined unit prefixes. --- All the units starting with the given prefixes will be included within the set. --- @param #SET_UNIT self --- @param #string Prefixes The prefix of which the unit name starts with. --- @return #SET_UNIT self -function SET_UNIT:FilterPrefixes( Prefixes ) - if not self.Filter.UnitPrefixes then - self.Filter.UnitPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.UnitPrefixes[Prefix] = Prefix - end - return self -end - ---- Builds a set of units having a radar of give types. --- All the units having a radar of a given type will be included within the set. --- @param #SET_UNIT self --- @param #table RadarTypes The radar types. --- @return #SET_UNIT self -function SET_UNIT:FilterHasRadar( RadarTypes ) - - self.Filter.RadarTypes = self.Filter.RadarTypes or {} - if type( RadarTypes ) ~= "table" then - RadarTypes = { RadarTypes } - end - for RadarTypeID, RadarType in pairs( RadarTypes ) do - self.Filter.RadarTypes[RadarType] = RadarType - end - return self -end - ---- Builds a set of SEADable units. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterHasSEAD() - - self.Filter.SEAD = true - return self -end - - - ---- Starts the filtering. --- @param #SET_UNIT self --- @return #SET_UNIT self -function SET_UNIT:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:AddInDatabase( Event ) - self:F3( { Event } ) - - if not self.Database[Event.IniDCSUnitName] then - self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) - self:T3( self.Database[Event.IniDCSUnitName] ) - end - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_UNIT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the UNIT --- @return #table The UNIT -function SET_UNIT:FindInDatabase( Event ) - self:E( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } ) - - - return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName] -end - ---- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. --- @param #SET_UNIT self --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnit( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence completely in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsCompletelyInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT presence not in a @{Zone}, providing the UNIT and optional parameters to the called function. --- @param #SET_UNIT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. --- @return #SET_UNIT self -function SET_UNIT:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Unit#UNIT UnitObject - function( ZoneObject, UnitObject ) - if UnitObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Returns map of unit types. --- @param #SET_UNIT self --- @return #map<#string,#number> A map of the unit types found. The key is the UnitTypeName and the value is the amount of unit types found. -function SET_UNIT:GetUnitTypes() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = {} - - for UnitID, UnitData in pairs( self:GetSet() ) do - local TextUnit = UnitData -- Wrapper.Unit#UNIT - if TextUnit:IsAlive() then - local UnitType = TextUnit:GetTypeName() - - if not UnitTypes[UnitType] then - UnitTypes[UnitType] = 1 - else - UnitTypes[UnitType] = UnitTypes[UnitType] + 1 - end - end - end - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return UnitTypes -end - - ---- Returns a comma separated string of the unit types with a count in the @{Set}. --- @param #SET_UNIT self --- @return #string The unit types string -function SET_UNIT:GetUnitTypesText() - self:F2() - - local MT = {} -- Message Text - local UnitTypes = self:GetUnitTypes() - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return table.concat( MT, ", " ) -end - ---- Returns map of unit threat levels. --- @param #SET_UNIT self --- @return #table. -function SET_UNIT:GetUnitThreatLevels() - self:F2() - - local UnitThreatLevels = {} - - for UnitID, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - if ThreatUnit:IsAlive() then - local UnitThreatLevel, UnitThreatLevelText = ThreatUnit:GetThreatLevel() - local ThreatUnitName = ThreatUnit:GetName() - - UnitThreatLevels[UnitThreatLevel] = UnitThreatLevels[UnitThreatLevel] or {} - UnitThreatLevels[UnitThreatLevel].UnitThreatLevelText = UnitThreatLevelText - UnitThreatLevels[UnitThreatLevel].Units = UnitThreatLevels[UnitThreatLevel].Units or {} - UnitThreatLevels[UnitThreatLevel].Units[ThreatUnitName] = ThreatUnit - end - end - - return UnitThreatLevels -end - ---- Calculate the maxium A2G threat level of the SET_UNIT. --- @param #SET_UNIT self -function SET_UNIT:CalculateThreatLevelA2G() - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( self:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - return MaxThreatLevelA2G - -end - - ---- Returns if the @{Set} has targets having a radar (of a given type). --- @param #SET_UNIT self --- @param Dcs.DCSWrapper.Unit#Unit.RadarType RadarType --- @return #number The amount of radars in the Set with the given type -function SET_UNIT:HasRadar( RadarType ) - self:F2( RadarType ) - - local RadarCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSensorTest = UnitData -- Wrapper.Unit#UNIT - local HasSensors - if RadarType then - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType ) - else - HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR ) - end - self:T3(HasSensors) - if HasSensors then - RadarCount = RadarCount + 1 - end - end - - return RadarCount -end - ---- Returns if the @{Set} has targets that can be SEADed. --- @param #SET_UNIT self --- @return #number The amount of SEADable units in the Set -function SET_UNIT:HasSEAD() - self:F2() - - local SEADCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitSEAD = UnitData -- Wrapper.Unit#UNIT - if UnitSEAD:IsAlive() then - local UnitSEADAttributes = UnitSEAD:GetDesc().attributes - - local HasSEAD = UnitSEAD:HasSEAD() - - self:T3(HasSEAD) - if HasSEAD then - SEADCount = SEADCount + 1 - end - end - end - - return SEADCount -end - ---- Returns if the @{Set} has ground targets. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasGroundUnits() - self:F2() - - local GroundUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsGround() then - GroundUnitCount = GroundUnitCount + 1 - end - end - - return GroundUnitCount -end - ---- Returns if the @{Set} has friendly ground units. --- @param #SET_UNIT self --- @return #number The amount of ground targets in the Set. -function SET_UNIT:HasFriendlyUnits( FriendlyCoalition ) - self:F2() - - local FriendlyUnitCount = 0 - for UnitID, UnitData in pairs( self:GetSet()) do - local UnitTest = UnitData -- Wrapper.Unit#UNIT - if UnitTest:IsFriendly( FriendlyCoalition ) then - FriendlyUnitCount = FriendlyUnitCount + 1 - end - end - - return FriendlyUnitCount -end - - - ------ Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.PlayersAlive ) --- --- return self ---end --- --- ------ Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. ----- @param #SET_UNIT self ----- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. ----- @return #SET_UNIT self ---function SET_UNIT:ForEachClient( IteratorFunction, ... ) --- self:F2( arg ) --- --- self:ForEach( IteratorFunction, arg, self.Clients ) --- --- return self ---end - - ---- --- @param #SET_UNIT self --- @param Wrapper.Unit#UNIT MUnit --- @return #SET_UNIT self -function SET_UNIT:IsIncludeObject( MUnit ) - self:F2( MUnit ) - local MUnitInclude = true - - if self.Filter.Coalitions then - local MUnitCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - self:T3( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then - MUnitCoalition = true - end - end - MUnitInclude = MUnitInclude and MUnitCoalition - end - - if self.Filter.Categories then - local MUnitCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then - MUnitCategory = true - end - end - MUnitInclude = MUnitInclude and MUnitCategory - end - - if self.Filter.Types then - local MUnitType = false - for TypeID, TypeName in pairs( self.Filter.Types ) do - self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) - if TypeName == MUnit:GetTypeName() then - MUnitType = true - end - end - MUnitInclude = MUnitInclude and MUnitType - end - - if self.Filter.Countries then - local MUnitCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) - if country.id[CountryName] == MUnit:GetCountry() then - MUnitCountry = true - end - end - MUnitInclude = MUnitInclude and MUnitCountry - end - - if self.Filter.UnitPrefixes then - local MUnitPrefix = false - for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do - self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) - if string.find( MUnit:GetName(), UnitPrefix, 1 ) then - MUnitPrefix = true - end - end - MUnitInclude = MUnitInclude and MUnitPrefix - end - - if self.Filter.RadarTypes then - local MUnitRadar = false - for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do - self:T3( { "Radar:", RadarType } ) - if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then - if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability. - self:T3( "RADAR Found" ) - end - MUnitRadar = true - end - end - MUnitInclude = MUnitInclude and MUnitRadar - end - - if self.Filter.SEAD then - local MUnitSEAD = false - if MUnit:HasSEAD() == true then - self:T3( "SEAD Found" ) - MUnitSEAD = true - end - MUnitInclude = MUnitInclude and MUnitSEAD - end - - self:T2( MUnitInclude ) - return MUnitInclude -end - - ---- SET_CLIENT - ---- SET_CLIENT class --- @type SET_CLIENT --- @extends Core.Set#SET_BASE -SET_CLIENT = { - ClassName = "SET_CLIENT", - Clients = {}, - Filter = { - Coalitions = nil, - Categories = nil, - Types = nil, - Countries = nil, - ClientPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - plane = Unit.Category.AIRPLANE, - helicopter = Unit.Category.HELICOPTER, - ground = Unit.Category.GROUND_UNIT, - ship = Unit.Category.SHIP, - structure = Unit.Category.STRUCTURE, - }, - }, -} - - ---- Creates a new SET_CLIENT object, building a set of clients belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #SET_CLIENT self --- @return #SET_CLIENT --- @usage --- -- Define a new SET_CLIENT Object. This DBObject will contain a reference to all Clients. --- DBObject = SET_CLIENT:New() -function SET_CLIENT:New() - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CLIENTS ) ) - - return self -end - ---- Add CLIENT(s) to SET_CLIENT. --- @param Core.Set#SET_CLIENT self --- @param #string AddClientNames A single name or an array of CLIENT names. --- @return self -function SET_CLIENT:AddClientsByName( AddClientNames ) - - local AddClientNamesArray = ( type( AddClientNames ) == "table" ) and AddClientNames or { AddClientNames } - - for AddClientID, AddClientName in pairs( AddClientNamesArray ) do - self:Add( AddClientName, CLIENT:FindByName( AddClientName ) ) - end - - return self -end - ---- Remove CLIENT(s) from SET_CLIENT. --- @param Core.Set#SET_CLIENT self --- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names. --- @return self -function SET_CLIENT:RemoveClientsByName( RemoveClientNames ) - - local RemoveClientNamesArray = ( type( RemoveClientNames ) == "table" ) and RemoveClientNames or { RemoveClientNames } - - for RemoveClientID, RemoveClientName in pairs( RemoveClientNamesArray ) do - self:Remove( RemoveClientName.ClientName ) - end - - return self -end - - ---- Finds a Client based on the Client Name. --- @param #SET_CLIENT self --- @param #string ClientName --- @return Wrapper.Client#CLIENT The found Client. -function SET_CLIENT:FindClient( ClientName ) - - local ClientFound = self.Set[ClientName] - return ClientFound -end - - - ---- Builds a set of clients of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_CLIENT self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_CLIENT self -function SET_CLIENT:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of clients out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_CLIENT self --- @param #string Categories Can take the following values: "plane", "helicopter", "ground", "ship". --- @return #SET_CLIENT self -function SET_CLIENT:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - - ---- Builds a set of clients of defined client types. --- Possible current types are those types known within DCS world. --- @param #SET_CLIENT self --- @param #string Types Can take those type strings known within DCS world. --- @return #SET_CLIENT self -function SET_CLIENT:FilterTypes( Types ) - if not self.Filter.Types then - self.Filter.Types = {} - end - if type( Types ) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs( Types ) do - self.Filter.Types[Type] = Type - end - return self -end - - ---- Builds a set of clients of defined countries. --- Possible current countries are those known within DCS world. --- @param #SET_CLIENT self --- @param #string Countries Can take those country strings known within DCS world. --- @return #SET_CLIENT self -function SET_CLIENT:FilterCountries( Countries ) - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type( Countries ) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs( Countries ) do - self.Filter.Countries[Country] = Country - end - return self -end - - ---- Builds a set of clients of defined client prefixes. --- All the clients starting with the given prefixes will be included within the set. --- @param #SET_CLIENT self --- @param #string Prefixes The prefix of which the client name starts with. --- @return #SET_CLIENT self -function SET_CLIENT:FilterPrefixes( Prefixes ) - if not self.Filter.ClientPrefixes then - self.Filter.ClientPrefixes = {} - end - if type( Prefixes ) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs( Prefixes ) do - self.Filter.ClientPrefixes[Prefix] = Prefix - end - return self -end - - - - ---- Starts the filtering. --- @param #SET_CLIENT self --- @return #SET_CLIENT self -function SET_CLIENT:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_CLIENT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the CLIENT --- @return #table The CLIENT -function SET_CLIENT:AddInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_CLIENT self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the CLIENT --- @return #table The CLIENT -function SET_CLIENT:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Iterate the SET_CLIENT and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters. --- @param #SET_CLIENT self --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClient( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence completely in a @{Zone}, providing the CLIENT and optional parameters to the called function. --- @param #SET_CLIENT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClientInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Client#CLIENT ClientObject - function( ZoneObject, ClientObject ) - if ClientObject:IsInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT presence not in a @{Zone}, providing the CLIENT and optional parameters to the called function. --- @param #SET_CLIENT self --- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. --- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. --- @return #SET_CLIENT self -function SET_CLIENT:ForEachClientNotInZone( ZoneObject, IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set, - --- @param Core.Zone#ZONE_BASE ZoneObject - -- @param Wrapper.Client#CLIENT ClientObject - function( ZoneObject, ClientObject ) - if ClientObject:IsNotInZone( ZoneObject ) then - return true - else - return false - end - end, { ZoneObject } ) - - return self -end - ---- --- @param #SET_CLIENT self --- @param Wrapper.Client#CLIENT MClient --- @return #SET_CLIENT self -function SET_CLIENT:IsIncludeObject( MClient ) - self:F2( MClient ) - - local MClientInclude = true - - if MClient then - local MClientName = MClient.UnitName - - if self.Filter.Coalitions then - local MClientCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName ) - self:T3( { "Coalition:", ClientCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == ClientCoalitionID then - MClientCoalition = true - end - end - self:T( { "Evaluated Coalition", MClientCoalition } ) - MClientInclude = MClientInclude and MClientCoalition - end - - if self.Filter.Categories then - local MClientCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName ) - self:T3( { "Category:", ClientCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == ClientCategoryID then - MClientCategory = true - end - end - self:T( { "Evaluated Category", MClientCategory } ) - MClientInclude = MClientInclude and MClientCategory - end - - if self.Filter.Types then - local MClientType = false - for TypeID, TypeName in pairs( self.Filter.Types ) do - self:T3( { "Type:", MClient:GetTypeName(), TypeName } ) - if TypeName == MClient:GetTypeName() then - MClientType = true - end - end - self:T( { "Evaluated Type", MClientType } ) - MClientInclude = MClientInclude and MClientType - end - - if self.Filter.Countries then - local MClientCountry = false - for CountryID, CountryName in pairs( self.Filter.Countries ) do - local ClientCountryID = _DATABASE:GetCountryFromClientTemplate(MClientName) - self:T3( { "Country:", ClientCountryID, country.id[CountryName], CountryName } ) - if country.id[CountryName] and country.id[CountryName] == ClientCountryID then - MClientCountry = true - end - end - self:T( { "Evaluated Country", MClientCountry } ) - MClientInclude = MClientInclude and MClientCountry - end - - if self.Filter.ClientPrefixes then - local MClientPrefix = false - for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do - self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } ) - if string.find( MClient.UnitName, ClientPrefix, 1 ) then - MClientPrefix = true - end - end - self:T( { "Evaluated Prefix", MClientPrefix } ) - MClientInclude = MClientInclude and MClientPrefix - end - end - - self:T2( MClientInclude ) - return MClientInclude -end - ---- SET_AIRBASE - ---- SET_AIRBASE class --- @type SET_AIRBASE --- @extends Core.Set#SET_BASE -SET_AIRBASE = { - ClassName = "SET_AIRBASE", - Airbases = {}, - Filter = { - Coalitions = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - Categories = { - airdrome = Airbase.Category.AIRDROME, - helipad = Airbase.Category.HELIPAD, - ship = Airbase.Category.SHIP, - }, - }, -} - - ---- Creates a new SET_AIRBASE object, building a set of airbases belonging to a coalitions and categories. --- @param #SET_AIRBASE self --- @return #SET_AIRBASE self --- @usage --- -- Define a new SET_AIRBASE Object. The DatabaseSet will contain a reference to all Airbases. --- DatabaseSet = SET_AIRBASE:New() -function SET_AIRBASE:New() - -- Inherits from BASE - local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.AIRBASES ) ) - - return self -end - ---- Add AIRBASEs to SET_AIRBASE. --- @param Core.Set#SET_AIRBASE self --- @param #string AddAirbaseNames A single name or an array of AIRBASE names. --- @return self -function SET_AIRBASE:AddAirbasesByName( AddAirbaseNames ) - - local AddAirbaseNamesArray = ( type( AddAirbaseNames ) == "table" ) and AddAirbaseNames or { AddAirbaseNames } - - for AddAirbaseID, AddAirbaseName in pairs( AddAirbaseNamesArray ) do - self:Add( AddAirbaseName, AIRBASE:FindByName( AddAirbaseName ) ) - end - - return self -end - ---- Remove AIRBASEs from SET_AIRBASE. --- @param Core.Set#SET_AIRBASE self --- @param Wrapper.Airbase#AIRBASE RemoveAirbaseNames A single name or an array of AIRBASE names. --- @return self -function SET_AIRBASE:RemoveAirbasesByName( RemoveAirbaseNames ) - - local RemoveAirbaseNamesArray = ( type( RemoveAirbaseNames ) == "table" ) and RemoveAirbaseNames or { RemoveAirbaseNames } - - for RemoveAirbaseID, RemoveAirbaseName in pairs( RemoveAirbaseNamesArray ) do - self:Remove( RemoveAirbaseName.AirbaseName ) - end - - return self -end - - ---- Finds a Airbase based on the Airbase Name. --- @param #SET_AIRBASE self --- @param #string AirbaseName --- @return Wrapper.Airbase#AIRBASE The found Airbase. -function SET_AIRBASE:FindAirbase( AirbaseName ) - - local AirbaseFound = self.Set[AirbaseName] - return AirbaseFound -end - - - ---- Builds a set of airbases of coalitions. --- Possible current coalitions are red, blue and neutral. --- @param #SET_AIRBASE self --- @param #string Coalitions Can take the following values: "red", "blue", "neutral". --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterCoalitions( Coalitions ) - if not self.Filter.Coalitions then - self.Filter.Coalitions = {} - end - if type( Coalitions ) ~= "table" then - Coalitions = { Coalitions } - end - for CoalitionID, Coalition in pairs( Coalitions ) do - self.Filter.Coalitions[Coalition] = Coalition - end - return self -end - - ---- Builds a set of airbases out of categories. --- Possible current categories are plane, helicopter, ground, ship. --- @param #SET_AIRBASE self --- @param #string Categories Can take the following values: "airdrome", "helipad", "ship". --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterCategories( Categories ) - if not self.Filter.Categories then - self.Filter.Categories = {} - end - if type( Categories ) ~= "table" then - Categories = { Categories } - end - for CategoryID, Category in pairs( Categories ) do - self.Filter.Categories[Category] = Category - end - return self -end - ---- Starts the filtering. --- @param #SET_AIRBASE self --- @return #SET_AIRBASE self -function SET_AIRBASE:FilterStart() - - if _DATABASE then - self:_FilterStart() - end - - return self -end - - ---- Handles the Database to check on an event (birth) that the Object was added in the Database. --- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! --- @param #SET_AIRBASE self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the AIRBASE --- @return #table The AIRBASE -function SET_AIRBASE:AddInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Handles the Database to check on any event that Object exists in the Database. --- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! --- @param #SET_AIRBASE self --- @param Core.Event#EVENTDATA Event --- @return #string The name of the AIRBASE --- @return #table The AIRBASE -function SET_AIRBASE:FindInDatabase( Event ) - self:F3( { Event } ) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] -end - ---- Iterate the SET_AIRBASE and call an interator function for each AIRBASE, providing the AIRBASE and optional parameters. --- @param #SET_AIRBASE self --- @param #function IteratorFunction The function that will be called when there is an alive AIRBASE in the SET_AIRBASE. The function needs to accept a AIRBASE parameter. --- @return #SET_AIRBASE self -function SET_AIRBASE:ForEachAirbase( IteratorFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, arg, self.Set ) - - return self -end - ---- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Core.Point#POINT_VEC2}. --- @param #SET_AIRBASE self --- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}. --- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}. -function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 ) - self:F2( PointVec2 ) - - local NearestAirbase = self:FindNearestObjectFromPointVec2( PointVec2 ) - return NearestAirbase -end - - - ---- --- @param #SET_AIRBASE self --- @param Wrapper.Airbase#AIRBASE MAirbase --- @return #SET_AIRBASE self -function SET_AIRBASE:IsIncludeObject( MAirbase ) - self:F2( MAirbase ) - - local MAirbaseInclude = true - - if MAirbase then - local MAirbaseName = MAirbase:GetName() - - if self.Filter.Coalitions then - local MAirbaseCoalition = false - for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do - local AirbaseCoalitionID = _DATABASE:GetCoalitionFromAirbase( MAirbaseName ) - self:T3( { "Coalition:", AirbaseCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == AirbaseCoalitionID then - MAirbaseCoalition = true - end - end - self:T( { "Evaluated Coalition", MAirbaseCoalition } ) - MAirbaseInclude = MAirbaseInclude and MAirbaseCoalition - end - - if self.Filter.Categories then - local MAirbaseCategory = false - for CategoryID, CategoryName in pairs( self.Filter.Categories ) do - local AirbaseCategoryID = _DATABASE:GetCategoryFromAirbase( MAirbaseName ) - self:T3( { "Category:", AirbaseCategoryID, self.FilterMeta.Categories[CategoryName], CategoryName } ) - if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == AirbaseCategoryID then - MAirbaseCategory = true - end - end - self:T( { "Evaluated Category", MAirbaseCategory } ) - MAirbaseInclude = MAirbaseInclude and MAirbaseCategory - end - end - - self:T2( MAirbaseInclude ) - return MAirbaseInclude -end ---- This module contains the POINT classes. --- --- 1) @{Core.Point#POINT_VEC3} class, extends @{Core.Base#BASE} --- ================================================== --- The @{Core.Point#POINT_VEC3} class defines a 3D point in the simulator. --- --- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts. --- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums. --- --- 1.1) POINT_VEC3 constructor --- --------------------------- --- A new POINT_VEC3 instance can be created with: --- --- * @{#POINT_VEC3.New}(): a 3D point. --- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{Dcs.DCSTypes#Vec3}. --- --- --- 2) @{Core.Point#POINT_VEC2} class, extends @{Core.Point#POINT_VEC3} --- ========================================================= --- The @{Core.Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified. --- --- 2.1) POINT_VEC2 constructor --- --------------------------- --- A new POINT_VEC2 instance can be created with: --- --- * @{#POINT_VEC2.New}(): a 2D point, taking an additional height parameter. --- * @{#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{Dcs.DCSTypes#Vec2}. --- --- === --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-12: POINT_VEC3:**Translate( Distance, Angle )** added. --- --- 2016-08-06: Made PointVec3 and Vec3, PointVec2 and Vec2 terminology used in the code consistent. --- --- * Replaced method _Point_Vec3() to **Vec3**() where the code manages a Vec3. Replaced all references to the method. --- * Replaced method _Point_Vec2() to **Vec2**() where the code manages a Vec2. Replaced all references to the method. --- * Replaced method Random_Point_Vec3() to **RandomVec3**() where the code manages a Vec3. Replaced all references to the method. --- . --- === --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- ### Contributions: --- --- @module Point - ---- The POINT_VEC3 class --- @type POINT_VEC3 --- @extends Core.Base#BASE --- @field #number x The x coordinate in 3D space. --- @field #number y The y coordinate in 3D space. --- @field #number z The z coordiante in 3D space. --- @field Utilities.Utils#SMOKECOLOR SmokeColor --- @field Utilities.Utils#FLARECOLOR FlareColor --- @field #POINT_VEC3.RoutePointAltType RoutePointAltType --- @field #POINT_VEC3.RoutePointType RoutePointType --- @field #POINT_VEC3.RoutePointAction RoutePointAction -POINT_VEC3 = { - ClassName = "POINT_VEC3", - Metric = true, - RoutePointAltType = { - BARO = "BARO", - }, - RoutePointType = { - TurningPoint = "Turning Point", - }, - RoutePointAction = { - TurningPoint = "Turning Point", - }, -} - ---- The POINT_VEC2 class --- @type POINT_VEC2 --- @extends #POINT_VEC3 --- @field Dcs.DCSTypes#Distance x The x coordinate in meters. --- @field Dcs.DCSTypes#Distance y the y coordinate in meters. -POINT_VEC2 = { - ClassName = "POINT_VEC2", -} - - -do -- POINT_VEC3 - ---- RoutePoint AltTypes --- @type POINT_VEC3.RoutePointAltType --- @field BARO "BARO" - ---- RoutePoint Types --- @type POINT_VEC3.RoutePointType --- @field TurningPoint "Turning Point" - ---- RoutePoint Actions --- @type POINT_VEC3.RoutePointAction --- @field TurningPoint "Turning Point" - --- Constructor. - ---- Create a new POINT_VEC3 object. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. --- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing Upwards. --- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. --- @return Core.Point#POINT_VEC3 self -function POINT_VEC3:New( x, y, z ) - - local self = BASE:Inherit( self, BASE:New() ) - self.x = x - self.y = y - self.z = z - - return self -end - ---- Create a new POINT_VEC3 object from Vec3 coordinates. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. --- @return Core.Point#POINT_VEC3 self -function POINT_VEC3:NewFromVec3( Vec3 ) - - self = self:New( Vec3.x, Vec3.y, Vec3.z ) - self:F2( self ) - return self -end - - ---- Return the coordinates of the POINT_VEC3 in Vec3 format. --- @param #POINT_VEC3 self --- @return Dcs.DCSTypes#Vec3 The Vec3 coodinate. -function POINT_VEC3:GetVec3() - return { x = self.x, y = self.y, z = self.z } -end - ---- Return the coordinates of the POINT_VEC3 in Vec2 format. --- @param #POINT_VEC3 self --- @return Dcs.DCSTypes#Vec2 The Vec2 coodinate. -function POINT_VEC3:GetVec2() - return { x = self.x, y = self.z } -end - - ---- Return the x coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The x coodinate. -function POINT_VEC3:GetX() - return self.x -end - ---- Return the y coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The y coodinate. -function POINT_VEC3:GetY() - return self.y -end - ---- Return the z coordinate of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number The z coodinate. -function POINT_VEC3:GetZ() - return self.z -end - ---- Set the x coordinate of the POINT_VEC3. --- @param #number x The x coordinate. -function POINT_VEC3:SetX( x ) - self.x = x -end - ---- Set the y coordinate of the POINT_VEC3. --- @param #number y The y coordinate. -function POINT_VEC3:SetY( y ) - self.y = y -end - ---- Set the z coordinate of the POINT_VEC3. --- @param #number z The z coordinate. -function POINT_VEC3:SetZ( z ) - self.z = z -end - ---- Return a random Vec2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return Dcs.DCSTypes#Vec2 Vec2 -function POINT_VEC3:GetRandomVec2InRadius( OuterRadius, InnerRadius ) - self:F2( { OuterRadius, InnerRadius } ) - - local Theta = 2 * math.pi * math.random() - local Radials = math.random() + math.random() - if Radials > 1 then - Radials = 2 - Radials - end - - local RadialMultiplier - if InnerRadius and InnerRadius <= OuterRadius then - RadialMultiplier = ( OuterRadius - InnerRadius ) * Radials + InnerRadius - else - RadialMultiplier = OuterRadius * Radials - end - - local RandomVec2 - if OuterRadius > 0 then - RandomVec2 = { x = math.cos( Theta ) * RadialMultiplier + self:GetX(), y = math.sin( Theta ) * RadialMultiplier + self:GetZ() } - else - RandomVec2 = { x = self:GetX(), y = self:GetZ() } - end - - return RandomVec2 -end - ---- Return a random POINT_VEC2 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return #POINT_VEC2 -function POINT_VEC3:GetRandomPointVec2InRadius( OuterRadius, InnerRadius ) - self:F2( { OuterRadius, InnerRadius } ) - - return POINT_VEC2:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) -end - ---- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return Dcs.DCSTypes#Vec3 Vec3 -function POINT_VEC3:GetRandomVec3InRadius( OuterRadius, InnerRadius ) - - local RandomVec2 = self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) - local y = self:GetY() + math.random( InnerRadius, OuterRadius ) - local RandomVec3 = { x = RandomVec2.x, y = y, z = RandomVec2.z } - - return RandomVec3 -end - ---- Return a random POINT_VEC3 within an Outer Radius and optionally NOT within an Inner Radius of the POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance OuterRadius --- @param Dcs.DCSTypes#Distance InnerRadius --- @return #POINT_VEC3 -function POINT_VEC3:GetRandomPointVec3InRadius( OuterRadius, InnerRadius ) - - return POINT_VEC3:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) ) -end - - ---- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. -function POINT_VEC3:GetDirectionVec3( TargetPointVec3 ) - return { x = TargetPointVec3:GetX() - self:GetX(), y = TargetPointVec3:GetY() - self:GetY(), z = TargetPointVec3:GetZ() - self:GetZ() } -end - ---- Get a correction in radians of the real magnetic north of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #number CorrectionRadians The correction in radians. -function POINT_VEC3:GetNorthCorrectionRadians() - local TargetVec3 = self:GetVec3() - local lat, lon = coord.LOtoLL(TargetVec3) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2( north_posit.z - TargetVec3.z, north_posit.x - TargetVec3.x ) -end - - ---- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format. --- @return #number DirectionRadians The direction in radians. -function POINT_VEC3:GetDirectionRadians( DirectionVec3 ) - local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x ) - --DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians() - if DirectionRadians < 0 then - DirectionRadians = DirectionRadians + 2 * math.pi -- put dir in range of 0 to 2*pi ( the full circle ) - end - return DirectionRadians -end - ---- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Distance Distance The distance in meters. -function POINT_VEC3:Get2DDistance( TargetPointVec3 ) - local TargetVec3 = TargetPointVec3:GetVec3() - local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 -end - ---- Return the 3D distance in meters between the target POINT_VEC3 and the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return Dcs.DCSTypes#Distance Distance The distance in meters. -function POINT_VEC3:Get3DDistance( TargetPointVec3 ) - local TargetVec3 = TargetPointVec3:GetVec3() - local SourceVec3 = self:GetVec3() - return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5 -end - ---- Provides a Bearing / Range string --- @param #POINT_VEC3 self --- @param #number AngleRadians The angle in randians --- @param #number Distance The distance --- @return #string The BR Text -function POINT_VEC3:ToStringBR( AngleRadians, Distance ) - - AngleRadians = UTILS.Round( UTILS.ToDegree( AngleRadians ), 0 ) - if self:IsMetric() then - Distance = UTILS.Round( Distance / 1000, 2 ) - else - Distance = UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) - end - - local s = string.format( '%03d', AngleRadians ) .. ' for ' .. Distance - - s = s .. self:GetAltitudeText() -- When the POINT is a VEC2, there will be no altitude shown. - - return s -end - ---- Provides a Bearing / Range string --- @param #POINT_VEC3 self --- @param #number AngleRadians The angle in randians --- @param #number Distance The distance --- @return #string The BR Text -function POINT_VEC3:ToStringLL( acc, DMS ) - - acc = acc or 3 - local lat, lon = coord.LOtoLL( self:GetVec3() ) - return UTILS.tostringLL(lat, lon, acc, DMS) -end - ---- Return the altitude text of the POINT_VEC3. --- @param #POINT_VEC3 self --- @return #string Altitude text. -function POINT_VEC3:GetAltitudeText() - if self:IsMetric() then - return ' at ' .. UTILS.Round( self:GetY(), 0 ) - else - return ' at ' .. UTILS.Round( UTILS.MetersToFeet( self:GetY() ), 0 ) - end -end - ---- Return a BR string from a POINT_VEC3 to the POINT_VEC3. --- @param #POINT_VEC3 self --- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3. --- @return #string The BR text. -function POINT_VEC3:GetBRText( TargetPointVec3 ) - local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 ) - local AngleRadians = self:GetDirectionRadians( DirectionVec3 ) - local Distance = self:Get2DDistance( TargetPointVec3 ) - return self:ToStringBR( AngleRadians, Distance ) -end - ---- Sets the POINT_VEC3 metric or NM. --- @param #POINT_VEC3 self --- @param #boolean Metric true means metric, false means NM. -function POINT_VEC3:SetMetric( Metric ) - self.Metric = Metric -end - ---- Gets if the POINT_VEC3 is metric or NM. --- @param #POINT_VEC3 self --- @return #boolean Metric true means metric, false means NM. -function POINT_VEC3:IsMetric() - return self.Metric -end - ---- Add a Distance in meters from the POINT_VEC3 horizontal plane, with the given angle, and calculate the new POINT_VEC3. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. --- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. --- @return #POINT_VEC3 The new calculated POINT_VEC3. -function POINT_VEC3:Translate( Distance, Angle ) - local SX = self:GetX() - local SZ = self:GetZ() - local Radians = Angle / 180 * math.pi - local TX = Distance * math.cos( Radians ) + SX - local TZ = Distance * math.sin( Radians ) + SZ - - return POINT_VEC3:New( TX, self:GetY(), TZ ) -end - - - ---- Build an air type route point. --- @param #POINT_VEC3 self --- @param #POINT_VEC3.RoutePointAltType AltType The altitude type. --- @param #POINT_VEC3.RoutePointType Type The route point type. --- @param #POINT_VEC3.RoutePointAction Action The route point action. --- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. --- @param #boolean SpeedLocked true means the speed is locked. --- @return #table The route point. -function POINT_VEC3:RoutePointAir( AltType, Type, Action, Speed, SpeedLocked ) - self:F2( { AltType, Type, Action, Speed, SpeedLocked } ) - - local RoutePoint = {} - RoutePoint.x = self:GetX() - RoutePoint.y = self:GetZ() - RoutePoint.alt = self:GetY() - RoutePoint.alt_type = AltType - - RoutePoint.type = Type - RoutePoint.action = Action - - RoutePoint.speed = Speed / 3.6 - RoutePoint.speed_locked = true - --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] - - - RoutePoint.task = {} - RoutePoint.task.id = "ComboTask" - RoutePoint.task.params = {} - RoutePoint.task.params.tasks = {} - - - return RoutePoint -end - ---- Build an ground type route point. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Speed Speed Speed in km/h. --- @param #POINT_VEC3.RoutePointAction Formation The route point Formation. --- @return #table The route point. -function POINT_VEC3:RoutePointGround( Speed, Formation ) - self:F2( { Formation, Speed } ) - - local RoutePoint = {} - RoutePoint.x = self:GetX() - RoutePoint.y = self:GetZ() - - RoutePoint.action = Formation or "" - - - RoutePoint.speed = Speed / 3.6 - RoutePoint.speed_locked = true - --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] - - - RoutePoint.task = {} - RoutePoint.task.id = "ComboTask" - RoutePoint.task.params = {} - RoutePoint.task.params.tasks = {} - - - return RoutePoint -end - - ---- Smokes the point in a color. --- @param #POINT_VEC3 self --- @param Utilities.Utils#SMOKECOLOR SmokeColor -function POINT_VEC3:Smoke( SmokeColor ) - self:F2( { SmokeColor } ) - trigger.action.smoke( self:GetVec3(), SmokeColor ) -end - ---- Smoke the POINT_VEC3 Green. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeGreen() - self:F2() - self:Smoke( SMOKECOLOR.Green ) -end - ---- Smoke the POINT_VEC3 Red. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeRed() - self:F2() - self:Smoke( SMOKECOLOR.Red ) -end - ---- Smoke the POINT_VEC3 White. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeWhite() - self:F2() - self:Smoke( SMOKECOLOR.White ) -end - ---- Smoke the POINT_VEC3 Orange. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeOrange() - self:F2() - self:Smoke( SMOKECOLOR.Orange ) -end - ---- Smoke the POINT_VEC3 Blue. --- @param #POINT_VEC3 self -function POINT_VEC3:SmokeBlue() - self:F2() - self:Smoke( SMOKECOLOR.Blue ) -end - ---- Flares the point in a color. --- @param #POINT_VEC3 self --- @param Utilities.Utils#FLARECOLOR FlareColor --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:Flare( FlareColor, Azimuth ) - self:F2( { FlareColor } ) - trigger.action.signalFlare( self:GetVec3(), FlareColor, Azimuth and Azimuth or 0 ) -end - ---- Flare the POINT_VEC3 White. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareWhite( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.White, Azimuth ) -end - ---- Flare the POINT_VEC3 Yellow. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareYellow( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Yellow, Azimuth ) -end - ---- Flare the POINT_VEC3 Green. --- @param #POINT_VEC3 self --- @param Dcs.DCSTypes#Azimuth (optional) Azimuth The azimuth of the flare direction. The default azimuth is 0. -function POINT_VEC3:FlareGreen( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Green, Azimuth ) -end - ---- Flare the POINT_VEC3 Red. --- @param #POINT_VEC3 self -function POINT_VEC3:FlareRed( Azimuth ) - self:F2( Azimuth ) - self:Flare( FLARECOLOR.Red, Azimuth ) -end - -end - -do -- POINT_VEC2 - - - ---- POINT_VEC2 constructor. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. --- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. --- @param Dcs.DCSTypes#Distance LandHeightAdd (optional) The default height if required to be evaluated will be the land height of the x, y coordinate. You can specify an extra height to be added to the land height. --- @return Core.Point#POINT_VEC2 -function POINT_VEC2:New( x, y, LandHeightAdd ) - - local LandHeight = land.getHeight( { ["x"] = x, ["y"] = y } ) - - LandHeightAdd = LandHeightAdd or 0 - LandHeight = LandHeight + LandHeightAdd - - self = BASE:Inherit( self, POINT_VEC3:New( x, LandHeight, y ) ) - self:F2( self ) - - return self -end - ---- Create a new POINT_VEC2 object from Vec2 coordinates. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 point. --- @return Core.Point#POINT_VEC2 self -function POINT_VEC2:NewFromVec2( Vec2, LandHeightAdd ) - - local LandHeight = land.getHeight( Vec2 ) - - LandHeightAdd = LandHeightAdd or 0 - LandHeight = LandHeight + LandHeightAdd - - self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) - self:F2( self ) - - return self -end - ---- Create a new POINT_VEC2 object from Vec3 coordinates. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. --- @return Core.Point#POINT_VEC2 self -function POINT_VEC2:NewFromVec3( Vec3 ) - - local self = BASE:Inherit( self, BASE:New() ) - local Vec2 = { x = Vec3.x, y = Vec3.z } - - local LandHeight = land.getHeight( Vec2 ) - - self = BASE:Inherit( self, POINT_VEC3:New( Vec2.x, LandHeight, Vec2.y ) ) - self:F2( self ) - - return self -end - ---- Return the x coordinate of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The x coodinate. -function POINT_VEC2:GetX() - return self.x -end - ---- Return the y coordinate of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The y coodinate. -function POINT_VEC2:GetY() - return self.z -end - ---- Return the altitude of the land at the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #number The land altitude. -function POINT_VEC2:GetAlt() - return land.getHeight( { x = self.x, y = self.z } ) -end - ---- Set the x coordinate of the POINT_VEC2. --- @param #number x The x coordinate. -function POINT_VEC2:SetX( x ) - self.x = x -end - ---- Set the y coordinate of the POINT_VEC2. --- @param #number y The y coordinate. -function POINT_VEC2:SetY( y ) - self.z = y -end - - - ---- Calculate the distance from a reference @{#POINT_VEC2}. --- @param #POINT_VEC2 self --- @param #POINT_VEC2 PointVec2Reference The reference @{#POINT_VEC2}. --- @return Dcs.DCSTypes#Distance The distance from the reference @{#POINT_VEC2} in meters. -function POINT_VEC2:DistanceFromPointVec2( PointVec2Reference ) - self:F2( PointVec2Reference ) - - local Distance = ( ( PointVec2Reference:GetX() - self:GetX() ) ^ 2 + ( PointVec2Reference:GetY() - self:GetY() ) ^2 ) ^0.5 - - self:T2( Distance ) - return Distance -end - ---- Calculate the distance from a reference @{Dcs.DCSTypes#Vec2}. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{Dcs.DCSTypes#Vec2}. --- @return Dcs.DCSTypes#Distance The distance from the reference @{Dcs.DCSTypes#Vec2} in meters. -function POINT_VEC2:DistanceFromVec2( Vec2Reference ) - self:F2( Vec2Reference ) - - local Distance = ( ( Vec2Reference.x - self:GetX() ) ^ 2 + ( Vec2Reference.y - self:GetY() ) ^2 ) ^0.5 - - self:T2( Distance ) - return Distance -end - - ---- Return no text for the altitude of the POINT_VEC2. --- @param #POINT_VEC2 self --- @return #string Empty string. -function POINT_VEC2:GetAltitudeText() - return '' -end - ---- Add a Distance in meters from the POINT_VEC2 orthonormal plane, with the given angle, and calculate the new POINT_VEC2. --- @param #POINT_VEC2 self --- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. --- @param Dcs.DCSTypes#Angle Angle The Angle in degrees. --- @return #POINT_VEC2 The new calculated POINT_VEC2. -function POINT_VEC2:Translate( Distance, Angle ) - local SX = self:GetX() - local SY = self:GetY() - local Radians = Angle / 180 * math.pi - local TX = Distance * math.cos( Radians ) + SX - local TY = Distance * math.sin( Radians ) + SY - - return POINT_VEC2:New( TX, TY ) -end - -end - - ---- This module contains the MESSAGE class. --- --- 1) @{Core.Message#MESSAGE} class, extends @{Core.Base#BASE} --- ================================================= --- Message System to display Messages to Clients, Coalitions or All. --- Messages are shown on the display panel for an amount of seconds, and will then disappear. --- Messages can contain a category which is indicating the category of the message. --- --- 1.1) MESSAGE construction methods --- --------------------------------- --- Messages are created with @{Core.Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet. --- To send messages, you need to use the To functions. --- --- 1.2) Send messages with MESSAGE To methods --- ------------------------------------------ --- Messages are sent to: --- --- * Clients with @{Core.Message#MESSAGE.ToClient}. --- * Coalitions with @{Core.Message#MESSAGE.ToCoalition}. --- * All Players with @{Core.Message#MESSAGE.ToAll}. --- --- @module Message --- @author FlightControl - ---- The MESSAGE class --- @type MESSAGE --- @extends Core.Base#BASE -MESSAGE = { - ClassName = "MESSAGE", - MessageCategory = 0, - MessageID = 0, -} - - ---- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients. --- @param self --- @param #string MessageText is the text of the Message. --- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel. --- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ". --- @return #MESSAGE --- @usage --- -- Create a series of new Messages. --- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". --- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win". --- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". --- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score". --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" ) --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" ) --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score") -function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { MessageText, MessageDuration, MessageCategory } ) - - -- When no MessageCategory is given, we don't show it as a title... - if MessageCategory and MessageCategory ~= "" then - if MessageCategory:sub(-1) ~= "\n" then - self.MessageCategory = MessageCategory .. ": " - else - self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n" - end - else - self.MessageCategory = "" - end - - self.MessageDuration = MessageDuration or 5 - self.MessageTime = timer.getTime() - self.MessageText = MessageText - - self.MessageSent = false - self.MessageGroup = false - self.MessageCoalition = false - - return self -end - ---- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player". --- @param #MESSAGE self --- @param Wrapper.Client#CLIENT Client is the Group of the Client. --- @return #MESSAGE --- @usage --- -- Send the 2 messages created with the @{New} method to the Client Group. --- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1. --- ClientGroup = Group.getByName( "ClientGroup" ) --- --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- or --- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup ) --- or --- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ) --- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ) --- MessageClient1:ToClient( ClientGroup ) --- MessageClient2:ToClient( ClientGroup ) -function MESSAGE:ToClient( Client ) - self:F( Client ) - - if Client and Client:GetClientGroupID() then - - local ClientGroupID = Client:GetClientGroupID() - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end - ---- Sends a MESSAGE to a Group. --- @param #MESSAGE self --- @param Wrapper.Group#GROUP Group is the Group. --- @return #MESSAGE -function MESSAGE:ToGroup( Group ) - self:F( Group.GroupName ) - - if Group then - - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end ---- Sends a MESSAGE to the Blue coalition. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the BLUE coalition. --- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() --- or --- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue() --- or --- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageBLUE:ToBlue() -function MESSAGE:ToBlue() - self:F() - - self:ToCoalition( coalition.side.BLUE ) - - return self -end - ---- Sends a MESSAGE to the Red Coalition. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the RED coalition. --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() --- or --- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed() --- or --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageRED:ToRed() -function MESSAGE:ToRed( ) - self:F() - - self:ToCoalition( coalition.side.RED ) - - return self -end - ---- Sends a MESSAGE to a Coalition. --- @param #MESSAGE self --- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. --- @return #MESSAGE --- @usage --- -- Send a message created with the @{New} method to the RED coalition. --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) --- or --- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED ) --- or --- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ) --- MessageRED:ToCoalition( coalition.side.RED ) -function MESSAGE:ToCoalition( CoalitionSide ) - self:F( CoalitionSide ) - - if CoalitionSide then - self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration ) - trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration ) - end - - return self -end - ---- Sends a MESSAGE to all players. --- @param #MESSAGE self --- @return #MESSAGE --- @usage --- -- Send a message created to all players. --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() --- or --- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll() --- or --- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ) --- MessageAll:ToAll() -function MESSAGE:ToAll() - self:F() - - self:ToCoalition( coalition.side.RED ) - self:ToCoalition( coalition.side.BLUE ) - - return self -end - - - ------ The MESSAGEQUEUE class ----- @type MESSAGEQUEUE ---MESSAGEQUEUE = { --- ClientGroups = {}, --- CoalitionSides = {} ---} --- ---function MESSAGEQUEUE:New( RefreshInterval ) --- local self = BASE:Inherit( self, BASE:New() ) --- self:F( { RefreshInterval } ) --- --- self.RefreshInterval = RefreshInterval --- --- --self.DisplayFunction = routines.scheduleFunction( self._DisplayMessages, { self }, 0, RefreshInterval ) --- self.DisplayFunction = SCHEDULER:New( self, self._DisplayMessages, {}, 0, RefreshInterval ) --- --- return self ---end --- ------ This function is called automatically by the MESSAGEQUEUE scheduler. ---function MESSAGEQUEUE:_DisplayMessages() --- --- -- First we display all messages that a coalition needs to receive... Also those who are not in a client (CA module clients...). --- for CoalitionSideID, CoalitionSideData in pairs( self.CoalitionSides ) do --- for MessageID, MessageData in pairs( CoalitionSideData.Messages ) do --- if MessageData.MessageSent == false then --- --trigger.action.outTextForCoalition( CoalitionSideID, MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageSent = true --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- end --- --- -- Then we send the messages for each individual client, but also to be included are those Coalition messages for the Clients who belong to a coalition. --- -- Because the Client messages will overwrite the Coalition messages (for that Client). --- for ClientGroupName, ClientGroupData in pairs( self.ClientGroups ) do --- for MessageID, MessageData in pairs( ClientGroupData.Messages ) do --- if MessageData.MessageGroup == false then --- trigger.action.outTextForGroup( Group.getByName(ClientGroupName):getID(), MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageGroup = true --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- --- -- Now check if the Client also has messages that belong to the Coalition of the Client... --- for CoalitionSideID, CoalitionSideData in pairs( self.CoalitionSides ) do --- for MessageID, MessageData in pairs( CoalitionSideData.Messages ) do --- local CoalitionGroup = Group.getByName( ClientGroupName ) --- if CoalitionGroup and CoalitionGroup:getCoalition() == CoalitionSideID then --- if MessageData.MessageCoalition == false then --- trigger.action.outTextForGroup( Group.getByName(ClientGroupName):getID(), MessageData.MessageCategory .. '\n' .. MessageData.MessageText:gsub("\n$",""):gsub("\n$",""), MessageData.MessageDuration ) --- MessageData.MessageCoalition = true --- end --- end --- local MessageTimeLeft = ( MessageData.MessageTime + MessageData.MessageDuration ) - timer.getTime() --- if MessageTimeLeft <= 0 then --- MessageData = nil --- end --- end --- end --- end --- --- return true ---end --- ------ The _MessageQueue object is created when the MESSAGE class module is loaded. -----_MessageQueue = MESSAGEQUEUE:New( 0.5 ) --- ---- This module contains the **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes. --- ## Finite State Machines (FSM) are design patterns allowing efficient (long-lasting) processes and workflows. --- --- ![Banner Image](..\Presentations\FSM\Dia1.JPG) --- --- A FSM can only be in one of a finite number of states. --- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. --- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. --- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. --- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. --- --- The FSM class supports a **hierarchical implementation of a Finite State Machine**, --- that is, it allows to **embed existing FSM implementations in a master FSM**. --- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. --- --- ![Workflow Example](..\Presentations\FSM\Dia2.JPG) --- --- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, --- orders him to destroy x targets and account the results. --- Other examples of ready made FSM could be: --- --- * route a plane to a zone flown by a human --- * detect targets by an AI and report to humans --- * account for destroyed targets by human players --- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle --- * let an AI patrol a zone --- --- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, --- because **the goal of MOOSE is to simplify mission design complexity for mission building**. --- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. --- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, --- and tailored** by mission designers through **the implementation of Transition Handlers**. --- Each of these FSM implementation classes start either with: --- --- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. --- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. --- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. --- --- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. --- --- ##__Dislaimer:__ --- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. --- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) --- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. --- Additionally, I've added extendability and created an API that allows seamless FSM implementation. --- --- === --- --- # 1) @{Core.Fsm#FSM} class, extends @{Core.Base#BASE} --- --- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG) --- --- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. --- The derived FSM\_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component. --- --- Finite State Machines have **Transition Rules**, **Transition Handlers** and **Event Triggers**. --- --- The **Transition Rules** define the "Process Flow Boundaries", that is, --- the path that can be followed hopping from state to state upon triggered events. --- If an event is triggered, and there is no valid path found for that event, --- an error will be raised and the FSM will stop functioning. --- --- The **Transition Handlers** are special methods that can be defined by the mission designer, following a defined syntax. --- If the FSM object finds a method of such a handler, then the method will be called by the FSM, passing specific parameters. --- The method can then define its own custom logic to implement the FSM workflow, and to conduct other actions. --- --- The **Event Triggers** are methods that are defined by the FSM, which the mission designer can use to implement the workflow. --- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. --- --- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. --- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. --- --- ## 1.1) FSM Linear Transitions --- --- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. --- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. --- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. --- --- ### 1.1.1) FSM Transition Rules --- --- The FSM has transition rules that it follows and validates, as it walks the process. --- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. --- --- The method @{#FSM.AddTransition}() specifies a new possible Transition Rule for the FSM. --- --- The initial state can be defined using the method @{#FSM.SetStartState}(). The default start state of an FSM is "None". --- --- Find below an example of a Linear Transition Rule definition for an FSM. --- --- local Fsm3Switch = FSM:New() -- #FsmDemo --- FsmSwitch:SetStartState( "Off" ) --- FsmSwitch:AddTransition( "Off", "SwitchOn", "On" ) --- FsmSwitch:AddTransition( "Off", "SwitchMiddle", "Middle" ) --- FsmSwitch:AddTransition( "On", "SwitchOff", "Off" ) --- FsmSwitch:AddTransition( "Middle", "SwitchOff", "Off" ) --- --- The above code snippet models a 3-way switch Linear Transition: --- --- * It can be switched **On** by triggering event **SwitchOn**. --- * It can be switched to the **Middle** position, by triggering event **SwitchMiddle**. --- * It can be switched **Off** by triggering event **SwitchOff**. --- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. --- --- ### Some additional comments: --- --- Note that Linear Transition Rules **can be declared in a few variations**: --- --- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. --- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. --- --- The below code snippet shows how the two last lines can be rewritten and consensed. --- --- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) --- --- ### 1.1.2) Transition Handling --- --- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG) --- --- An FSM transitions in **4 moments** when an Event is being triggered and processed. --- The mission designer can define for each moment specific logic within methods implementations following a defined API syntax. --- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be triggered. --- --- * To handle **State** transition moments, create methods starting with OnLeave or OnEnter concatenated with the State name. --- * To handle **Event** transition moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. --- --- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition!** --- --- Transition Handler methods need to follow the above specified naming convention, but are also passed parameters from the FSM. --- These parameters are on the correct order: From, Event, To: --- --- * From = A string containing the From state. --- * Event = A string containing the Event name that was triggered. --- * To = A string containing the To state. --- --- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). --- --- ### 1.1.3) Event Triggers --- --- ![Event Triggers](..\Presentations\FSM\Dia5.JPG) --- --- The FSM creates for each Event two **Event Trigger methods**. --- There are two modes how Events can be triggered, which is **synchronous** and **asynchronous**: --- --- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. --- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. --- --- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. --- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. --- --- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. --- --- function FSM:OnAfterEvent( From, Event, To, Amount ) --- self:E( { Amount = Amount } ) --- end --- --- local Amount = 1 --- FSM:__Event( 5, Amount ) --- --- Amount = Amount + 1 --- FSM:Event( Text, Amount ) --- --- In this example, the **:OnAfterEvent**() Transition Handler implementation will get called when **Event** is being triggered. --- Before we go into more detail, let's look at the last 4 lines of the example. --- The last line triggers synchronously the **Event**, and passes Amount as a parameter. --- The 3rd last line of the example triggers asynchronously **Event**. --- Event will be processed after 5 seconds, and Amount is given as a parameter. --- --- The output of this little code fragment will be: --- --- * Amount = 2 --- * Amount = 2 --- --- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! --- --- ### 1.1.4) Linear Transition Example --- --- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) --- --- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare. --- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build. --- Have a look at the source code. The source code is also further explained below in this section. --- --- The example creates a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to state **Green**. --- Two Linear Transition Rules are created, where upon the event **Switch**, --- the FsmDemo will transition from state **Green** to **Red** and from **Red** back to **Green**. --- --- ![Transition Example](..\Presentations\FSM\Dia6.JPG) --- --- local FsmDemo = FSM:New() -- #FsmDemo --- FsmDemo:SetStartState( "Green" ) --- FsmDemo:AddTransition( "Green", "Switch", "Red" ) --- FsmDemo:AddTransition( "Red", "Switch", "Green" ) --- --- In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. --- The next code implements this through the event handling method **OnAfterSwitch**. --- --- ![Transition Flow](..\Presentations\FSM\Dia7.JPG) --- --- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) --- self:E( { From, Event, To, FsmUnit } ) --- --- if From == "Green" then --- FsmUnit:Flare(FLARECOLOR.Green) --- else --- if From == "Red" then --- FsmUnit:Flare(FLARECOLOR.Red) --- end --- end --- self:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. --- end --- --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds. --- --- The OnAfterSwitch implements a loop. The last line of the code fragment triggers the Switch Event within 5 seconds. --- Upon the event execution (after 5 seconds), the OnAfterSwitch method is called of FsmDemo (cfr. the double point notation!!! ":"). --- The OnAfterSwitch method receives from the FSM the 3 transition parameter details ( From, Event, To ), --- and one additional parameter that was given when the event was triggered, which is in this case the Unit that is used within OnSwitchAfter. --- --- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) --- --- For debugging reasons the received parameters are traced within the DCS.log. --- --- self:E( { From, Event, To, FsmUnit } ) --- --- The method will check if the From state received is either "Green" or "Red" and will flare the respective color from the FsmUnit. --- --- if From == "Green" then --- FsmUnit:Flare(FLARECOLOR.Green) --- else --- if From == "Red" then --- FsmUnit:Flare(FLARECOLOR.Red) --- end --- end --- --- It is important that the Switch event is again triggered, otherwise, the FsmDemo would stop working after having the first Event being handled. --- --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. --- --- The below code fragment extends the FsmDemo, demonstrating multiple **From states declared as a table**, adding a **Linear Transition Rule**. --- The new event **Stop** will cancel the Switching process. --- The transition for event Stop can be executed if the current state of the FSM is either "Red" or "Green". --- --- local FsmDemo = FSM:New() -- #FsmDemo --- FsmDemo:SetStartState( "Green" ) --- FsmDemo:AddTransition( "Green", "Switch", "Red" ) --- FsmDemo:AddTransition( "Red", "Switch", "Green" ) --- FsmDemo:AddTransition( { "Red", "Green" }, "Stop", "Stopped" ) --- --- The transition for event Stop can also be simplified, as any current state of the FSM is valid. --- --- FsmDemo:AddTransition( "*", "Stop", "Stopped" ) --- --- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. --- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. --- --- ## 1.5) FSM Hierarchical Transitions --- --- Hierarchical Transitions allow to re-use readily available and implemented FSMs. --- This becomes in very useful for mission building, where mission designers build complex processes and workflows, --- combining smaller FSMs to one single FSM. --- --- The FSM can embed **Sub-FSMs** that will execute and return **multiple possible Return (End) States**. --- Depending upon **which state is returned**, the main FSM can continue the flow **triggering specific events**. --- --- The method @{#FSM.AddProcess}() adds a new Sub-FSM to the FSM. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- YYYY-MM-DD: CLASS:**NewFunction**( Params ) replaces CLASS:_OldFunction_( Params ) --- YYYY-MM-DD: CLASS:**NewFunction( Params )** added --- --- Hereby the change log: --- --- * 2016-12-18: Released. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements. --- --- ### Authors: --- --- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. --- --- @module Fsm - -do -- FSM - - --- FSM class - -- @type FSM - -- @extends Core.Base#BASE - FSM = { - ClassName = "FSM", - } - - --- Creates a new FSM object. - -- @param #FSM self - -- @return #FSM - function FSM:New( FsmT ) - - -- Inherits from BASE - self = BASE:Inherit( self, BASE:New() ) - - self.options = options or {} - self.options.subs = self.options.subs or {} - self.current = self.options.initial or 'none' - self.Events = {} - self.subs = {} - self.endstates = {} - - self.Scores = {} - - self._StartState = "none" - self._Transitions = {} - self._Processes = {} - self._EndStates = {} - self._Scores = {} - - self.CallScheduler = SCHEDULER:New( self ) - - - return self - end - - - --- Sets the start state of the FSM. - -- @param #FSM self - -- @param #string State A string defining the start state. - function FSM:SetStartState( State ) - - self._StartState = State - self.current = State - end - - - --- Returns the start state of the FSM. - -- @param #FSM self - -- @return #string A string containing the start state. - function FSM:GetStartState() - - return self._StartState or {} - end - - --- Add a new transition rule to the FSM. - -- A transition rule defines when and if the FSM can transition from a state towards another state upon a triggered event. - -- @param #FSM self - -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. - -- @param #string Event The Event name. - -- @param #string To The To state. - function FSM:AddTransition( From, Event, To ) - - local Transition = {} - Transition.From = From - Transition.Event = Event - Transition.To = To - - self:E( Transition ) - - self._Transitions[Transition] = Transition - self:_eventmap( self.Events, Transition ) - end - - - --- Returns a table of the transition rules defined within the FSM. - -- @return #table - function FSM:GetTransitions() - - return self._Transitions or {} - end - - --- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task. - -- @param #FSM self - -- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states. - -- @param #string Event The Event name. - -- @param Core.Fsm#FSM_PROCESS Process An sub-process FSM. - -- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM. - -- @return Core.Fsm#FSM_PROCESS The SubFSM. - function FSM:AddProcess( From, Event, Process, ReturnEvents ) - self:E( { From, Event, Process, ReturnEvents } ) - - local Sub = {} - Sub.From = From - Sub.Event = Event - Sub.fsm = Process - Sub.StartEvent = "Start" - Sub.ReturnEvents = ReturnEvents - - self._Processes[Sub] = Sub - - self:_submap( self.subs, Sub, nil ) - - self:AddTransition( From, Event, From ) - - return Process - end - - - --- Returns a table of the SubFSM rules defined within the FSM. - -- @return #table - function FSM:GetProcesses() - - return self._Processes or {} - end - - function FSM:GetProcess( From, Event ) - - for ProcessID, Process in pairs( self:GetProcesses() ) do - if Process.From == From and Process.Event == Event then - self:E( Process ) - return Process.fsm - end - end - - error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" ) - end - - --- Adds an End state. - function FSM:AddEndState( State ) - - self._EndStates[State] = State - self.endstates[State] = State - end - - --- Returns the End states. - function FSM:GetEndStates() - - return self._EndStates or {} - end - - - --- Adds a score for the FSM to be achieved. - -- @param #FSM self - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM self - function FSM:AddScore( State, ScoreText, Score ) - self:F2( { State, ScoreText, Score } ) - - self._Scores[State] = self._Scores[State] or {} - self._Scores[State].ScoreText = ScoreText - self._Scores[State].Score = Score - - return self - end - - --- Adds a score for the FSM_PROCESS to be achieved. - -- @param #FSM self - -- @param #string From is the From State of the main process. - -- @param #string Event is the Event of the main process. - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM self - function FSM:AddScoreProcess( From, Event, State, ScoreText, Score ) - self:F2( { Event, State, ScoreText, Score } ) - - local Process = self:GetProcess( From, Event ) - - self:E( { Process = Process._Name, Scores = Process._Scores, State = State, ScoreText = ScoreText, Score = Score } ) - Process._Scores[State] = Process._Scores[State] or {} - Process._Scores[State].ScoreText = ScoreText - Process._Scores[State].Score = Score - - return Process - end - - --- Returns a table with the scores defined. - function FSM:GetScores() - - return self._Scores or {} - end - - --- Returns a table with the Subs defined. - function FSM:GetSubs() - - return self.options.subs - end - - - function FSM:LoadCallBacks( CallBackTable ) - - for name, callback in pairs( CallBackTable or {} ) do - self[name] = callback - end - - end - - function FSM:_eventmap( Events, EventStructure ) - - local Event = EventStructure.Event - local __Event = "__" .. EventStructure.Event - self[Event] = self[Event] or self:_create_transition(Event) - self[__Event] = self[__Event] or self:_delayed_transition(Event) - self:T( "Added methods: " .. Event .. ", " .. __Event ) - Events[Event] = self.Events[Event] or { map = {} } - self:_add_to_map( Events[Event].map, EventStructure ) - - end - - function FSM:_submap( subs, sub, name ) - self:F( { sub = sub, name = name } ) - subs[sub.From] = subs[sub.From] or {} - subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {} - - -- Make the reference table weak. - -- setmetatable( subs[sub.From][sub.Event], { __mode = "k" } ) - - subs[sub.From][sub.Event][sub] = {} - subs[sub.From][sub.Event][sub].fsm = sub.fsm - subs[sub.From][sub.Event][sub].StartEvent = sub.StartEvent - subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop. - subs[sub.From][sub.Event][sub].name = name - subs[sub.From][sub.Event][sub].fsmparent = self - end - - - function FSM:_call_handler(handler, params) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, unpack(params) ) - end - end - - function FSM._handler( self, EventName, ... ) - - self:E( { EventName, ... } ) - - local Can, to = self:can( EventName ) - self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) - - if Can then - local from = self.current - local params = { from, EventName, to, ... } - - if self:_call_handler("onbefore" .. EventName, params) == false - or self:_call_handler("OnBefore" .. EventName, params) == false - or self:_call_handler("onleave" .. from, params) == false - or self:_call_handler("OnLeave" .. from, params) == false then - return false - end - - self.current = to - - local execute = true - - local subtable = self:_gosub( from, EventName ) - for _, sub in pairs( subtable ) do - --if sub.nextevent then - -- self:F2( "nextevent = " .. sub.nextevent ) - -- self[sub.nextevent]( self ) - --end - self:E( "calling sub start event: " .. sub.StartEvent ) - sub.fsm.fsmparent = self - sub.fsm.ReturnEvents = sub.ReturnEvents - sub.fsm[sub.StartEvent]( sub.fsm ) - execute = false - end - - local fsmparent, Event = self:_isendstate( to ) - if fsmparent and Event then - self:F2( { "end state: ", fsmparent, Event } ) - self:_call_handler("onenter" .. to, params) - self:_call_handler("OnEnter" .. to, params) - self:_call_handler("onafter" .. EventName, params) - self:_call_handler("OnAfter" .. EventName, params) - self:_call_handler("onstatechange", params) - fsmparent[Event]( fsmparent ) - execute = false - end - - if execute then - -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! - --if from ~= to then - self:_call_handler("onenter" .. to, params) - self:_call_handler("OnEnter" .. to, params) - --end - - self:_call_handler("onafter" .. EventName, params) - self:_call_handler("OnAfter" .. EventName, params) - - self:_call_handler("onstatechange", params) - end - end - - return nil - end - - function FSM:_delayed_transition( EventName ) - self:E( { EventName = EventName } ) - return function( self, DelaySeconds, ... ) - self:T( "Delayed Event: " .. EventName ) - local CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) - self:T( { CallID = CallID } ) - end - end - - function FSM:_create_transition( EventName ) - self:E( { Event = EventName } ) - return function( self, ... ) return self._handler( self, EventName , ... ) end - end - - function FSM:_gosub( ParentFrom, ParentEvent ) - local fsmtable = {} - if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then - self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } ) - return self.subs[ParentFrom][ParentEvent] - else - return {} - end - end - - function FSM:_isendstate( Current ) - local FSMParent = self.fsmparent - if FSMParent and self.endstates[Current] then - self:E( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } ) - FSMParent.current = Current - local ParentFrom = FSMParent.current - self:E( ParentFrom ) - self:E( self.ReturnEvents ) - local Event = self.ReturnEvents[Current] - self:E( { ParentFrom, Event, self.ReturnEvents } ) - if Event then - return FSMParent, Event - else - self:E( { "Could not find parent event name for state ", ParentFrom } ) - end - end - - return nil - end - - function FSM:_add_to_map( Map, Event ) - self:F3( { Map, Event } ) - if type(Event.From) == 'string' then - Map[Event.From] = Event.To - else - for _, From in ipairs(Event.From) do - Map[From] = Event.To - end - end - self:T3( { Map, Event } ) - end - - function FSM:GetState() - return self.current - end - - - function FSM:Is( State ) - return self.current == State - end - - function FSM:is(state) - return self.current == state - end - - function FSM:can(e) - self:E( { e, self.Events, self.Events[e] } ) - local Event = self.Events[e] - self:F3( { self.current, Event } ) - local To = Event and Event.map[self.current] or Event.map['*'] - return To ~= nil, To - end - - function FSM:cannot(e) - return not self:can(e) - end - -end - -do -- FSM_CONTROLLABLE - - --- FSM_CONTROLLABLE class - -- @type FSM_CONTROLLABLE - -- @field Wrapper.Controllable#CONTROLLABLE Controllable - -- @extends Core.Fsm#FSM - FSM_CONTROLLABLE = { - ClassName = "FSM_CONTROLLABLE", - } - - --- Creates a new FSM_CONTROLLABLE object. - -- @param #FSM_CONTROLLABLE self - -- @param #table FSMT Finite State Machine Table - -- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @return #FSM_CONTROLLABLE - function FSM_CONTROLLABLE:New( FSMT, Controllable ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE - - if Controllable then - self:SetControllable( Controllable ) - end - - return self - end - - --- Sets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @param #FSM_CONTROLLABLE self - -- @param Wrapper.Controllable#CONTROLLABLE FSMControllable - -- @return #FSM_CONTROLLABLE - function FSM_CONTROLLABLE:SetControllable( FSMControllable ) - self:F( FSMControllable ) - self.Controllable = FSMControllable - end - - --- Gets the CONTROLLABLE object that the FSM_CONTROLLABLE governs. - -- @param #FSM_CONTROLLABLE self - -- @return Wrapper.Controllable#CONTROLLABLE - function FSM_CONTROLLABLE:GetControllable() - return self.Controllable - end - - function FSM_CONTROLLABLE:_call_handler( handler, params ) - - local ErrorHandler = function( errmsg ) - - env.info( "Error in SCHEDULER function:" .. errmsg ) - if debug ~= nil then - env.info( debug.traceback() ) - end - - return errmsg - end - - if self[handler] then - self:E( "Calling " .. handler ) - return xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler ) - --return self[handler]( self, self.Controllable, unpack( params ) ) - end - end - -end - -do -- FSM_PROCESS - - --- FSM_PROCESS class - -- @type FSM_PROCESS - -- @field Tasking.Task#TASK Task - -- @extends Core.Fsm#FSM_CONTROLLABLE - FSM_PROCESS = { - ClassName = "FSM_PROCESS", - } - - --- Creates a new FSM_PROCESS object. - -- @param #FSM_PROCESS self - -- @return #FSM_PROCESS - function FSM_PROCESS:New( Controllable, Task ) - - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS - - self:F( Controllable, Task ) - - self:Assign( Controllable, Task ) - - return self - end - - function FSM_PROCESS:Init( FsmProcess ) - self:E( "No Initialisation" ) - end - - --- Creates a new FSM_PROCESS object based on this FSM_PROCESS. - -- @param #FSM_PROCESS self - -- @return #FSM_PROCESS - function FSM_PROCESS:Copy( Controllable, Task ) - self:E( { self:GetClassNameAndID() } ) - - local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS - - NewFsm:Assign( Controllable, Task ) - - -- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS - NewFsm:Init( self ) - - -- Set Start State - NewFsm:SetStartState( self:GetStartState() ) - - -- Copy Transitions - for TransitionID, Transition in pairs( self:GetTransitions() ) do - NewFsm:AddTransition( Transition.From, Transition.Event, Transition.To ) - end - - -- Copy Processes - for ProcessID, Process in pairs( self:GetProcesses() ) do - self:E( { Process} ) - local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents ) - end - - -- Copy End States - for EndStateID, EndState in pairs( self:GetEndStates() ) do - self:E( EndState ) - NewFsm:AddEndState( EndState ) - end - - -- Copy the score tables - for ScoreID, Score in pairs( self:GetScores() ) do - self:E( Score ) - NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score ) - end - - return NewFsm - end - - --- Sets the task of the process. - -- @param #FSM_PROCESS self - -- @param Tasking.Task#TASK Task - -- @return #FSM_PROCESS - function FSM_PROCESS:SetTask( Task ) - - self.Task = Task - - return self - end - - --- Gets the task of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.Task#TASK - function FSM_PROCESS:GetTask() - - return self.Task - end - - --- Gets the mission of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.Mission#MISSION - function FSM_PROCESS:GetMission() - - return self.Task.Mission - end - - --- Gets the mission of the process. - -- @param #FSM_PROCESS self - -- @return Tasking.CommandCenter#COMMANDCENTER - function FSM_PROCESS:GetCommandCenter() - - return self:GetTask():GetMission():GetCommandCenter() - end - --- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP. - - --- Send a message of the @{Task} to the Group of the Unit. --- @param #FSM_PROCESS self -function FSM_PROCESS:Message( Message ) - self:F( { Message = Message } ) - - local CC = self:GetCommandCenter() - local TaskGroup = self.Controllable:GetGroup() - - local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit - PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets. - local Callsign = self.Controllable:GetCallsign() - local Prefix = Callsign and " @ " .. Callsign .. PlayerName or "" - - Message = Prefix .. ": " .. Message - CC:MessageToGroup( Message, TaskGroup ) -end - - - - - --- Assign the process to a @{Unit} and activate the process. - -- @param #FSM_PROCESS self - -- @param Task.Tasking#TASK Task - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @return #FSM_PROCESS self - function FSM_PROCESS:Assign( ProcessUnit, Task ) - self:E( { Task, ProcessUnit } ) - - self:SetControllable( ProcessUnit ) - self:SetTask( Task ) - - --self.ProcessGroup = ProcessUnit:GetGroup() - - return self - end - - --- Adds a score for the FSM_PROCESS to be achieved. - -- @param #FSM_PROCESS self - -- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process). - -- @param #string ScoreText is a text describing the score that is given according the status. - -- @param #number Score is a number providing the score of the status. - -- @return #FSM_PROCESS self - function FSM_PROCESS:AddScore( State, ScoreText, Score ) - self:F2( { State, ScoreText, Score } ) - - self.Scores[State] = self.Scores[State] or {} - self.Scores[State].ScoreText = ScoreText - self.Scores[State].Score = Score - - return self - end - - function FSM_PROCESS:onenterAssigned( ProcessUnit ) - self:E( "Assign" ) - - self.Task:Assign() - end - - function FSM_PROCESS:onenterFailed( ProcessUnit ) - self:E( "Failed" ) - - self.Task:Fail() - end - - function FSM_PROCESS:onenterSuccess( ProcessUnit ) - self:E( "Success" ) - - self.Task:Success() - end - - --- StateMachine callback function for a FSM_PROCESS - -- @param #FSM_PROCESS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function FSM_PROCESS:onstatechange( ProcessUnit, From, Event, To, Dummy ) - self:E( { ProcessUnit, From, Event, To, Dummy, self:IsTrace() } ) - - if self:IsTrace() then - MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() - end - - self:E( self.Scores[To] ) - -- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects... - if self.Scores[To] then - - local Task = self.Task - local Scoring = Task:GetScoring() - if Scoring then - Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score ) - end - end - end - -end - -do -- FSM_TASK - - --- FSM_TASK class - -- @type FSM_TASK - -- @field Tasking.Task#TASK Task - -- @extends Core.Fsm#FSM - FSM_TASK = { - ClassName = "FSM_TASK", - } - - --- Creates a new FSM_TASK object. - -- @param #FSM_TASK self - -- @param #table FSMT - -- @param Tasking.Task#TASK Task - -- @param Wrapper.Unit#UNIT TaskUnit - -- @return #FSM_TASK - function FSM_TASK:New( FSMT ) - - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK - - self["onstatechange"] = self.OnStateChange - - return self - end - - function FSM_TASK:_call_handler( handler, params ) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, unpack( params ) ) - end - end - -end -- FSM_TASK - -do -- FSM_SET - - --- FSM_SET class - -- @type FSM_SET - -- @field Core.Set#SET_BASE Set - -- @extends Core.Fsm#FSM - FSM_SET = { - ClassName = "FSM_SET", - } - - --- Creates a new FSM_SET object. - -- @param #FSM_SET self - -- @param #table FSMT Finite State Machine Table - -- @param Set_SET_BASE FSMSet (optional) The Set object that the FSM_SET governs. - -- @return #FSM_SET - function FSM_SET:New( FSMSet ) - - -- Inherits from BASE - self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET - - if FSMSet then - self:Set( FSMSet ) - end - - return self - end - - --- Sets the SET_BASE object that the FSM_SET governs. - -- @param #FSM_SET self - -- @param Core.Set#SET_BASE FSMSet - -- @return #FSM_SET - function FSM_SET:Set( FSMSet ) - self:F( FSMSet ) - self.Set = FSMSet - end - - --- Gets the SET_BASE object that the FSM_SET governs. - -- @param #FSM_SET self - -- @return Core.Set#SET_BASE - function FSM_SET:Get() - return self.Controllable - end - - function FSM_SET:_call_handler( handler, params ) - if self[handler] then - self:E( "Calling " .. handler ) - return self[handler]( self, self.Set, unpack( params ) ) - end - end - -end -- FSM_SET - ---- This module contains the OBJECT class. --- --- 1) @{Wrapper.Object#OBJECT} class, extends @{Core.Base#BASE} --- =========================================================== --- The @{Wrapper.Object#OBJECT} class is a wrapper class to handle the DCS Object objects: --- --- * Support all DCS Object APIs. --- * Enhance with Object specific APIs not in the DCS Object API set. --- * Manage the "state" of the DCS Object. --- --- 1.1) OBJECT constructor: --- ------------------------------ --- The OBJECT class provides the following functions to construct a OBJECT instance: --- --- * @{Wrapper.Object#OBJECT.New}(): Create a OBJECT instance. --- --- 1.2) OBJECT methods: --- -------------------------- --- The following methods can be used to identify an Object object: --- --- * @{Wrapper.Object#OBJECT.GetID}(): Returns the ID of the Object object. --- --- === --- --- @module Object - ---- The OBJECT class --- @type OBJECT --- @extends Core.Base#BASE --- @field #string ObjectName The name of the Object. -OBJECT = { - ClassName = "OBJECT", - ObjectName = "", -} - ---- A DCSObject --- @type DCSObject --- @field id_ The ID of the controllable in DCS - ---- Create a new OBJECT from a DCSObject --- @param #OBJECT self --- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name --- @return #OBJECT self -function OBJECT:New( ObjectName, Test ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( ObjectName ) - self.ObjectName = ObjectName - - return self -end - - ---- Returns the unit's unique identifier. --- @param Wrapper.Object#OBJECT self --- @return Dcs.DCSWrapper.Object#Object.ID ObjectID --- @return #nil The DCS Object is not existing or alive. -function OBJECT:GetID() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - - if DCSObject then - local ObjectID = DCSObject:getID() - return ObjectID - end - - return nil -end - ---- Destroys the OBJECT. --- @param #OBJECT self --- @return #nil The DCS Unit is not existing or alive. -function OBJECT:Destroy() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - - if DCSObject then - - DCSObject:destroy() - end - - return nil -end - - - - ---- This module contains the IDENTIFIABLE class. --- --- 1) @{#IDENTIFIABLE} class, extends @{Wrapper.Object#OBJECT} --- =============================================================== --- The @{#IDENTIFIABLE} class is a wrapper class to handle the DCS Identifiable objects: --- --- * Support all DCS Identifiable APIs. --- * Enhance with Identifiable specific APIs not in the DCS Identifiable API set. --- * Manage the "state" of the DCS Identifiable. --- --- 1.1) IDENTIFIABLE constructor: --- ------------------------------ --- The IDENTIFIABLE class provides the following functions to construct a IDENTIFIABLE instance: --- --- * @{#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. --- --- 1.2) IDENTIFIABLE methods: --- -------------------------- --- The following methods can be used to identify an identifiable object: --- --- * @{#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. --- * @{#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. --- * @{#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. --- * @{#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. --- * @{#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. --- * @{#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. --- --- --- === --- --- @module Identifiable - ---- The IDENTIFIABLE class --- @type IDENTIFIABLE --- @extends Wrapper.Object#OBJECT --- @field #string IdentifiableName The name of the identifiable. -IDENTIFIABLE = { - ClassName = "IDENTIFIABLE", - IdentifiableName = "", -} - -local _CategoryName = { - [Unit.Category.AIRPLANE] = "Airplane", - [Unit.Category.HELICOPTER] = "Helicoper", - [Unit.Category.GROUND_UNIT] = "Ground Identifiable", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - } - ---- Create a new IDENTIFIABLE from a DCSIdentifiable --- @param #IDENTIFIABLE self --- @param Dcs.DCSWrapper.Identifiable#Identifiable IdentifiableName The DCS Identifiable name --- @return #IDENTIFIABLE self -function IDENTIFIABLE:New( IdentifiableName ) - local self = BASE:Inherit( self, OBJECT:New( IdentifiableName ) ) - self:F2( IdentifiableName ) - self.IdentifiableName = IdentifiableName - return self -end - ---- Returns if the Identifiable is alive. --- @param #IDENTIFIABLE self --- @return #boolean true if Identifiable is alive. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:IsAlive() - self:F3( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableIsAlive = DCSIdentifiable:isExist() - return IdentifiableIsAlive - end - - return false -end - - - - ---- Returns DCS Identifiable object name. --- The function provides access to non-activated objects too. --- @param #IDENTIFIABLE self --- @return #string The name of the DCS Identifiable. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetName() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableName = self.IdentifiableName - return IdentifiableName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - ---- Returns the type name of the DCS Identifiable. --- @param #IDENTIFIABLE self --- @return #string The type name of the DCS Identifiable. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetTypeName() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableTypeName = DCSIdentifiable:getTypeName() - self:T3( IdentifiableTypeName ) - return IdentifiableTypeName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - ---- Returns category of the DCS Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Object#Object.Category The category ID -function IDENTIFIABLE:GetCategory() - self:F2( self.ObjectName ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - local ObjectCategory = DCSObject:getCategory() - self:T3( ObjectCategory ) - return ObjectCategory - end - - return nil -end - - ---- Returns the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. --- @param #IDENTIFIABLE self --- @return #string The DCS Identifiable Category Name -function IDENTIFIABLE:GetCategoryName() - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCategoryName = _CategoryName[ self:GetDesc().category ] - return IdentifiableCategoryName - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Returns coalition of the Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The side of the coalition. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetCoalition() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCoalition = DCSIdentifiable:getCoalition() - self:T3( IdentifiableCoalition ) - return IdentifiableCoalition - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Returns country of the Identifiable. --- @param #IDENTIFIABLE self --- @return Dcs.DCScountry#country.id The country identifier. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetCountry() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableCountry = DCSIdentifiable:getCountry() - self:T3( IdentifiableCountry ) - return IdentifiableCountry - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - - - ---- Returns Identifiable descriptor. Descriptor type depends on Identifiable category. --- @param #IDENTIFIABLE self --- @return Dcs.DCSWrapper.Identifiable#Identifiable.Desc The Identifiable descriptor. --- @return #nil The DCS Identifiable is not existing or alive. -function IDENTIFIABLE:GetDesc() - self:F2( self.IdentifiableName ) - - local DCSIdentifiable = self:GetDCSObject() - - if DCSIdentifiable then - local IdentifiableDesc = DCSIdentifiable:getDesc() - self:T2( IdentifiableDesc ) - return IdentifiableDesc - end - - self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) - return nil -end - ---- Gets the CallSign of the IDENTIFIABLE, which is a blank by default. --- @param #IDENTIFIABLE self --- @return #string The CallSign of the IDENTIFIABLE. -function IDENTIFIABLE:GetCallsign() - return '' -end - - - - - - - - - ---- This module contains the POSITIONABLE class. --- --- 1) @{Wrapper.Positionable#POSITIONABLE} class, extends @{Wrapper.Identifiable#IDENTIFIABLE} --- =========================================================== --- The @{Wrapper.Positionable#POSITIONABLE} class is a wrapper class to handle the POSITIONABLE objects: --- --- * Support all DCS APIs. --- * Enhance with POSITIONABLE specific APIs not in the DCS API set. --- * Manage the "state" of the POSITIONABLE. --- --- 1.1) POSITIONABLE constructor: --- ------------------------------ --- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: --- --- * @{Wrapper.Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. --- --- 1.2) POSITIONABLE methods: --- -------------------------- --- The following methods can be used to identify an measurable object: --- --- * @{Wrapper.Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. --- * @{Wrapper.Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. --- --- === --- --- @module Positionable - ---- The POSITIONABLE class --- @type POSITIONABLE --- @extends Wrapper.Identifiable#IDENTIFIABLE --- @field #string PositionableName The name of the measurable. -POSITIONABLE = { - ClassName = "POSITIONABLE", - PositionableName = "", -} - ---- A DCSPositionable --- @type DCSPositionable --- @field id_ The ID of the controllable in DCS - ---- Create a new POSITIONABLE from a DCSPositionable --- @param #POSITIONABLE self --- @param Dcs.DCSWrapper.Positionable#Positionable PositionableName The POSITIONABLE name --- @return #POSITIONABLE self -function POSITIONABLE:New( PositionableName ) - local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) - - return self -end - ---- Returns the @{Dcs.DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Position The 3D position vectors of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetPositionVec3() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePosition = DCSPositionable:getPosition() - self:T3( PositionablePosition ) - return PositionablePosition - end - - return nil -end - ---- Returns the @{Dcs.DCSTypes#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec2 The 2D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVec2() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - - local PositionableVec2 = {} - PositionableVec2.x = PositionableVec3.x - PositionableVec2.y = PositionableVec3.z - - self:T2( PositionableVec2 ) - return PositionableVec2 - end - - return nil -end - ---- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetPointVec2() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - - local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - - self:T2( PositionablePointVec2 ) - return PositionablePointVec2 - end - - return nil -end - - ---- Returns a random @{Dcs.DCSTypes#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetRandomVec3( Radius ) - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePointVec3 = DCSPositionable:getPosition().p - local PositionableRandomVec3 = {} - local angle = math.random() * math.pi*2; - PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius; - PositionableRandomVec3.y = PositionablePointVec3.y - PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius; - - self:T3( PositionableRandomVec3 ) - return PositionableRandomVec3 - end - - return nil -end - ---- Returns the @{Dcs.DCSTypes#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVec3() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVec3 = DCSPositionable:getPosition().p - self:T3( PositionableVec3 ) - return PositionableVec3 - end - - return nil -end - ---- Returns the altitude of the POSITIONABLE. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Distance The altitude of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetAltitude() - self:F2() - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionablePointVec3 = DCSPositionable:getPoint() --Dcs.DCSTypes#Vec3 - return PositionablePointVec3.y - end - - return nil -end - ---- Returns if the Positionable is located above a runway. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #boolean true if Positionable is above a runway. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:IsAboveRunway() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - - local Vec2 = self:GetVec2() - local SurfaceType = land.getSurfaceType( Vec2 ) - local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - - self:T2( IsAboveRunway ) - return IsAboveRunway - end - - return nil -end - - - ---- Returns the POSITIONABLE heading in degrees. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #number The POSTIONABLE heading -function POSITIONABLE:GetHeading() - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - - local PositionablePosition = DCSPositionable:getPosition() - if PositionablePosition then - local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x ) - if PositionableHeading < 0 then - PositionableHeading = PositionableHeading + 2 * math.pi - end - PositionableHeading = PositionableHeading * 180 / math.pi - self:T2( PositionableHeading ) - return PositionableHeading - end - end - - return nil -end - - ---- Returns true if the POSITIONABLE is in the air. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #boolean true if in the air. --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:InAir() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableInAir = DCSPositionable:inAir() - self:T3( PositionableInAir ) - return PositionableInAir - end - - return nil -end - - ---- Returns the POSITIONABLE velocity vector. --- @param Wrapper.Positionable#POSITIONABLE self --- @return Dcs.DCSTypes#Vec3 The velocity vector --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVelocity() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local PositionableVelocityVec3 = DCSPositionable:getVelocity() - self:T3( PositionableVelocityVec3 ) - return PositionableVelocityVec3 - end - - return nil -end - ---- Returns the POSITIONABLE velocity in km/h. --- @param Wrapper.Positionable#POSITIONABLE self --- @return #number The velocity in km/h --- @return #nil The POSITIONABLE is not existing or alive. -function POSITIONABLE:GetVelocityKMH() - self:F2( self.PositionableName ) - - local DCSPositionable = self:GetDCSObject() - - if DCSPositionable then - local VelocityVec3 = self:GetVelocity() - local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - local Velocity = Velocity * 3.6 -- now it is in km/h. - self:T3( Velocity ) - return Velocity - end - - return nil -end - ---- Returns a message with the callsign embedded (if there is one). --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. --- @return Core.Message#MESSAGE -function POSITIONABLE:GetMessage( Message, Duration, Name ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - Name = Name or self:GetTypeName() - return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. Name .. ")" ) - end - - return nil -end - ---- Send a message to all coalitions. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToAll( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToAll() - end - - return nil -end - ---- Send a message to a coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition ) - end - - return nil -end - - ---- Send a message to the red coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTYpes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToRed( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToRed() - end - - return nil -end - ---- Send a message to the blue coalition. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToBlue( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToBlue() - end - - return nil -end - ---- Send a message to a client. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param Wrapper.Client#CLIENT Client The client object receiving the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToClient( Message, Duration, Client, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToClient( Client ) - end - - return nil -end - ---- Send a message to a @{Group}. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param Wrapper.Group#GROUP MessageGroup The GROUP object receiving the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - if DCSObject:isExist() then - self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup ) - end - end - - return nil -end - ---- Send a message to the players in the @{Group}. --- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message. --- @param #POSITIONABLE self --- @param #string Message The message text --- @param Dcs.DCSTypes#Duration Duration The duration of the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:Message( Message, Duration, Name ) - self:F2( { Message, Duration } ) - - local DCSObject = self:GetDCSObject() - if DCSObject then - self:GetMessage( Message, Duration, Name ):ToGroup( self ) - end - - return nil -end - - - - - ---- This module contains the CONTROLLABLE class. --- --- 1) @{Wrapper.Controllable#CONTROLLABLE} class, extends @{Wrapper.Positionable#POSITIONABLE} --- =========================================================== --- The @{Wrapper.Controllable#CONTROLLABLE} class is a wrapper class to handle the DCS Controllable objects: --- --- * Support all DCS Controllable APIs. --- * Enhance with Controllable specific APIs not in the DCS Controllable API set. --- * Handle local Controllable Controller. --- * Manage the "state" of the DCS Controllable. --- --- 1.1) CONTROLLABLE constructor --- ----------------------------- --- The CONTROLLABLE class provides the following functions to construct a CONTROLLABLE instance: --- --- * @{#CONTROLLABLE.New}(): Create a CONTROLLABLE instance. --- --- 1.2) CONTROLLABLE task methods --- ------------------------------ --- Several controllable task methods are available that help you to prepare tasks. --- These methods return a string consisting of the task description, which can then be given to either a @{Wrapper.Controllable#CONTROLLABLE.PushTask} or @{Wrapper.Controllable#SetTask} method to assign the task to the CONTROLLABLE. --- Tasks are specific for the category of the CONTROLLABLE, more specific, for AIR, GROUND or AIR and GROUND. --- Each task description where applicable indicates for which controllable category the task is valid. --- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. --- --- ### 1.2.1) Assigned task methods --- --- Assigned task methods make the controllable execute the task where the location of the (possible) targets of the task are known before being detected. --- This is different from the EnRoute tasks, where the targets of the task need to be detected before the task can be executed. --- --- Find below a list of the **assigned task** methods: --- --- * @{#CONTROLLABLE.TaskAttackControllable}: (AIR) Attack a Controllable. --- * @{#CONTROLLABLE.TaskAttackMapObject}: (AIR) Attacking the map object (building, structure, e.t.c). --- * @{#CONTROLLABLE.TaskAttackUnit}: (AIR) Attack the Unit. --- * @{#CONTROLLABLE.TaskBombing}: (AIR) Delivering weapon at the point on the ground. --- * @{#CONTROLLABLE.TaskBombingRunway}: (AIR) Delivering weapon on the runway. --- * @{#CONTROLLABLE.TaskEmbarking}: (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. --- * @{#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location. --- * @{#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne controllable. --- * @{#CONTROLLABLE.TaskFAC_AttackControllable}: (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. --- * @{#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire at a VEC2 point until ammunition is finished. --- * @{#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne controllable. --- * @{#CONTROLLABLE.TaskHold}: (GROUND) Hold ground controllable from moving. --- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable. --- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. --- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). --- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. --- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. --- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points. --- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point. --- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point. --- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone. --- * @{#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the controllable to an airbase. --- --- ### 1.2.2) EnRoute task methods --- --- EnRoute tasks require the targets of the task need to be detected by the controllable (using its sensors) before the task can be executed: --- --- * @{#CONTROLLABLE.EnRouteTaskAWACS}: (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- * @{#CONTROLLABLE.EnRouteTaskEngageControllable}: (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskEngageTargets}: (AIR) Engaging targets of defined types. --- * @{#CONTROLLABLE.EnRouteTaskEWR}: (AIR) Attack the Unit. --- * @{#CONTROLLABLE.EnRouteTaskFAC}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskFAC_EngageControllable}: (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. --- * @{#CONTROLLABLE.EnRouteTaskTanker}: (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- --- ### 1.2.3) Preparation task methods --- --- There are certain task methods that allow to tailor the task behaviour: --- --- * @{#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command. --- * @{#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks. --- * @{#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task. --- * @{#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition. --- --- ### 1.2.4) Obtain the mission from controllable templates --- --- Controllable templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a controllable and assign it to another: --- --- * @{#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. --- --- 1.3) CONTROLLABLE Command methods --- -------------------------- --- Controllable **command methods** prepare the execution of commands using the @{#CONTROLLABLE.SetCommand} method: --- --- * @{#CONTROLLABLE.CommandDoScript}: Do Script command. --- * @{#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command. --- --- 1.4) CONTROLLABLE Option methods --- ------------------------- --- Controllable **Option methods** change the behaviour of the Controllable while being alive. --- --- ### 1.4.1) Rule of Engagement: --- --- * @{#CONTROLLABLE.OptionROEWeaponFree} --- * @{#CONTROLLABLE.OptionROEOpenFire} --- * @{#CONTROLLABLE.OptionROEReturnFire} --- * @{#CONTROLLABLE.OptionROEEvadeFire} --- --- To check whether an ROE option is valid for a specific controllable, use: --- --- * @{#CONTROLLABLE.OptionROEWeaponFreePossible} --- * @{#CONTROLLABLE.OptionROEOpenFirePossible} --- * @{#CONTROLLABLE.OptionROEReturnFirePossible} --- * @{#CONTROLLABLE.OptionROEEvadeFirePossible} --- --- ### 1.4.2) Rule on thread: --- --- * @{#CONTROLLABLE.OptionROTNoReaction} --- * @{#CONTROLLABLE.OptionROTPassiveDefense} --- * @{#CONTROLLABLE.OptionROTEvadeFire} --- * @{#CONTROLLABLE.OptionROTVertical} --- --- To test whether an ROT option is valid for a specific controllable, use: --- --- * @{#CONTROLLABLE.OptionROTNoReactionPossible} --- * @{#CONTROLLABLE.OptionROTPassiveDefensePossible} --- * @{#CONTROLLABLE.OptionROTEvadeFirePossible} --- * @{#CONTROLLABLE.OptionROTVerticalPossible} --- --- === --- --- @module Controllable - ---- The CONTROLLABLE class --- @type CONTROLLABLE --- @extends Wrapper.Positionable#POSITIONABLE --- @field Dcs.DCSWrapper.Controllable#Controllable DCSControllable The DCS controllable class. --- @field #string ControllableName The name of the controllable. -CONTROLLABLE = { - ClassName = "CONTROLLABLE", - ControllableName = "", - WayPointFunctions = {}, -} - ---- Create a new CONTROLLABLE from a DCSControllable --- @param #CONTROLLABLE self --- @param Dcs.DCSWrapper.Controllable#Controllable ControllableName The DCS Controllable name --- @return #CONTROLLABLE self -function CONTROLLABLE:New( ControllableName ) - local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) - self:F2( ControllableName ) - self.ControllableName = ControllableName - - self.TaskScheduler = SCHEDULER:New( self ) - return self -end - --- DCS Controllable methods support. - ---- Get the controller for the CONTROLLABLE. --- @param #CONTROLLABLE self --- @return Dcs.DCSController#Controller -function CONTROLLABLE:_GetController() - self:F2( { self.ControllableName } ) - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local ControllableController = DCSControllable:getController() - self:T3( ControllableController ) - return ControllableController - end - - return nil -end - - - --- Tasks - ---- Popping current Task from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:PopCurrentTask() - self:F2() - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - Controller:popTask() - return self - end - - return nil -end - ---- Pushing Task on the queue from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:PushTask( DCSTask, WaitTime ) - self:F2() - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - - -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Controllable. - -- Controller:pushTask( DCSTask ) - - if WaitTime then - self.TaskScheduler:Schedule( Controller, Controller.pushTask, { DCSTask }, WaitTime ) - else - Controller:pushTask( DCSTask ) - end - - return self - end - - return nil -end - ---- Clearing the Task Queue and Setting the Task on the queue from the controllable. --- @param #CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local Controller = self:_GetController() - self:E(Controller) - - -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Controllable. - -- Controller.setTask( Controller, DCSTask ) - - if not WaitTime then - Controller:setTask( DCSTask ) - else - self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime ) - end - - return self - end - - return nil -end - - ---- Return a condition section for a controlled task. --- @param #CONTROLLABLE self --- @param Dcs.DCSTime#Time time --- @param #string userFlag --- @param #boolean userFlagValue --- @param #string condition --- @param Dcs.DCSTime#Time duration --- @param #number lastWayPoint --- return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskCondition( time, userFlag, userFlagValue, condition, duration, lastWayPoint ) - self:F2( { time, userFlag, userFlagValue, condition, duration, lastWayPoint } ) - - local DCSStopCondition = {} - DCSStopCondition.time = time - DCSStopCondition.userFlag = userFlag - DCSStopCondition.userFlagValue = userFlagValue - DCSStopCondition.condition = condition - DCSStopCondition.duration = duration - DCSStopCondition.lastWayPoint = lastWayPoint - - self:T3( { DCSStopCondition } ) - return DCSStopCondition -end - ---- Return a Controlled Task taking a Task and a TaskCondition. --- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#Task DCSTask --- @param #DCSStopCondition DCSStopCondition --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition ) - self:F2( { DCSTask, DCSStopCondition } ) - - local DCSTaskControlled - - DCSTaskControlled = { - id = 'ControlledTask', - params = { - task = DCSTask, - stopCondition = DCSStopCondition - } - } - - self:T3( { DCSTaskControlled } ) - return DCSTaskControlled -end - ---- Return a Combo Task taking an array of Tasks. --- @param #CONTROLLABLE self --- @param Dcs.DCSTasking.Task#TaskArray DCSTasks Array of @{Dcs.DCSTasking.Task#Task} --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskCombo( DCSTasks ) - self:F2( { DCSTasks } ) - - local DCSTaskCombo - - DCSTaskCombo = { - id = 'ComboTask', - params = { - tasks = DCSTasks - } - } - - self:T3( { DCSTaskCombo } ) - return DCSTaskCombo -end - ---- Return a WrappedAction Task taking a Command. --- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index ) - self:F2( { DCSCommand } ) - - local DCSTaskWrappedAction - - DCSTaskWrappedAction = { - id = "WrappedAction", - enabled = true, - number = Index, - auto = false, - params = { - action = DCSCommand, - }, - } - - self:T3( { DCSTaskWrappedAction } ) - return DCSTaskWrappedAction -end - ---- Executes a command action --- @param #CONTROLLABLE self --- @param Dcs.DCSCommand#Command DCSCommand --- @return #CONTROLLABLE self -function CONTROLLABLE:SetCommand( DCSCommand ) - self:F2( DCSCommand ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Controller = self:_GetController() - Controller:setCommand( DCSCommand ) - return self - end - - return nil -end - ---- Perform a switch waypoint command --- @param #CONTROLLABLE self --- @param #number FromWayPoint --- @param #number ToWayPoint --- @return Dcs.DCSTasking.Task#Task --- @usage --- --- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class. --- HeliGroup = GROUP:FindByName( "Helicopter" ) --- --- --- Route the helicopter back to the FARP after 60 seconds. --- -- We use the SCHEDULER class to do this. --- SCHEDULER:New( nil, --- function( HeliGroup ) --- local CommandRTB = HeliGroup:CommandSwitchWayPoint( 2, 8 ) --- HeliGroup:SetCommand( CommandRTB ) --- end, { HeliGroup }, 90 --- ) -function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint ) - self:F2( { FromWayPoint, ToWayPoint } ) - - local CommandSwitchWayPoint = { - id = 'SwitchWaypoint', - params = { - fromWaypointIndex = FromWayPoint, - goToWaypointIndex = ToWayPoint, - }, - } - - self:T3( { CommandSwitchWayPoint } ) - return CommandSwitchWayPoint -end - ---- Perform stop route command --- @param #CONTROLLABLE self --- @param #boolean StopRoute --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:CommandStopRoute( StopRoute, Index ) - self:F2( { StopRoute, Index } ) - - local CommandStopRoute = { - id = 'StopRoute', - params = { - value = StopRoute, - }, - } - - self:T3( { CommandStopRoute } ) - return CommandStopRoute -end - - --- TASKS FOR AIR CONTROLLABLES - - ---- (AIR) Attack a Controllable. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- AttackControllable = { - -- id = 'AttackControllable', - -- params = { - -- groupId = Group.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend, - -- attackQty = number, - -- directionEnabled = boolean, - -- direction = Azimuth, - -- altitudeEnabled = boolean, - -- altitude = Distance, - -- attackQtyLimit = boolean, - -- } - -- } - - local DirectionEnabled = nil - if Direction then - DirectionEnabled = true - end - - local AltitudeEnabled = nil - if Altitude then - AltitudeEnabled = true - end - - local DCSTask - DCSTask = { id = 'AttackControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - directionEnabled = DirectionEnabled, - direction = Direction, - altitudeEnabled = AltitudeEnabled, - altitude = Altitude, - attackQtyLimit = AttackQtyLimit, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Attack the Unit. --- @param #CONTROLLABLE self --- @param Wrapper.Unit#UNIT AttackUnit The unit. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack ) - self:F2( { self.ControllableName, AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack } ) - - -- AttackUnit = { - -- id = 'AttackUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- controllableAttack = boolean, - -- } - -- } - - local DCSTask - DCSTask = { id = 'AttackUnit', - params = { - altitudeEnabled = false, - unitId = AttackUnit:GetID(), - attackQtyLimit = AttackQtyLimit or false, - attackQty = AttackQty or 1, - expend = WeaponExpend or "Auto", - altitude = 2000, - directionEnabled = false, - groupAttack = false, - weaponType = WeaponType or 1073741822, - direction = Direction or 0, - }, - }, - - self:E( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon at the point on the ground. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackControllable and AttackUnit tasks. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskBombing( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- Bombing = { --- id = 'Bombing', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'Bombing', - params = { - point = Vec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point to hold the position. --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.ControllableName, Point, Altitude, Speed } ) - - -- pattern = enum AI.Task.OribtPattern, - -- point = Vec2, - -- point2 = Vec2, - -- speed = Distance, - -- altitude = Distance - - local LandHeight = land.getHeight( Point ) - - self:T3( { LandHeight } ) - - local DCSTask = { id = 'Orbit', - params = { pattern = AI.Task.OrbitPattern.CIRCLE, - point = Point, - speed = Speed, - altitude = Altitude + LandHeight - } - } - - - -- local AITask = { id = 'ControlledTask', - -- params = { task = { id = 'Orbit', - -- params = { pattern = AI.Task.OrbitPattern.CIRCLE, - -- point = Point, - -- speed = Speed, - -- altitude = Altitude + LandHeight - -- } - -- }, - -- stopCondition = { duration = Duration - -- } - -- } - -- } - -- ) - - return DCSTask -end - ---- (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude. --- @param #CONTROLLABLE self --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed ) - self:F2( { self.ControllableName, Altitude, Speed } ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local ControllablePoint = self:GetVec2() - return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed ) - end - - return nil -end - - - ---- (AIR) Hold position at the current position of the first unit of the controllable. --- @param #CONTROLLABLE self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskHoldPosition() - self:F2( { self.ControllableName } ) - - return self:TaskOrbitCircle( 30, 10 ) -end - - - - ---- (AIR) Attacking the map object (building, structure, e.t.c). --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point the map object is closest to. The distance between the point and the map object must not be greater than 2000 meters. Object id is not used here because Mission Editor doesn't support map object identificators. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskAttackMapObject( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- AttackMapObject = { --- id = 'AttackMapObject', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'AttackMapObject', - params = { - point = Vec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon on the runway. --- @param #CONTROLLABLE self --- @param Wrapper.Airbase#AIRBASE Airbase Airbase to attack. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) - --- BombingRunway = { --- id = 'BombingRunway', --- params = { --- runwayId = AirdromeId, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- controllableAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'BombingRunway', - params = { - point = Airbase:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Refueling from the nearest tanker. No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskRefueling() - self:F2( { self.ControllableName } ) - --- Refueling = { --- id = 'Refueling', --- params = {} --- } - - local DCSTask - DCSTask = { id = 'Refueling', - params = { - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR HELICOPTER) Landing at the ground. For helicopters only. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskLandAtVec2( Point, Duration ) - self:F2( { self.ControllableName, Point, Duration } ) - --- Land = { --- id= 'Land', --- params = { --- point = Vec2, --- durationFlag = boolean, --- duration = Time --- } --- } - - local DCSTask - if Duration and Duration > 0 then - DCSTask = { id = 'Land', - params = { - point = Point, - durationFlag = true, - duration = Duration, - }, - } - else - DCSTask = { id = 'Land', - params = { - point = Point, - durationFlag = false, - }, - } - end - - self:T3( DCSTask ) - return DCSTask -end - ---- (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS). --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint ) - self:F2( { self.ControllableName, Zone, Duration, RandomPoint } ) - - local Point - if RandomPoint then - Point = Zone:GetRandomVec2() - else - Point = Zone:GetVec2() - end - - local DCSTask = self:TaskLandAtVec2( Point, Duration ) - - self:T3( DCSTask ) - return DCSTask -end - - - ---- (AIR) Following another airborne controllable. --- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. --- If another controllable is on land the unit / controllable will orbit around. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE FollowControllable The controllable to be followed. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex ) - self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex } ) - --- Follow = { --- id = 'Follow', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number --- } --- } - - local LastWaypointIndexFlag = false - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { - id = 'Follow', - params = { - groupId = FollowControllable:GetID(), - pos = Vec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Escort another airborne controllable. --- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. --- The unit / controllable will also protect that controllable from threats of specified types. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. --- @param Dcs.DCSTypes#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. --- @param #number EngagementDistanceMax Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes ) - self:F2( { self.ControllableName, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) - --- Escort = { --- id = 'Escort', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number, --- engagementDistMax = Distance, --- targetTypes = array of AttributeName, --- } --- } - - local LastWaypointIndexFlag = false - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Escort', - params = { - groupId = FollowControllable:GetID(), - pos = Vec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex, - engagementDistMax = EngagementDistance, - targetTypes = TargetTypes, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - --- GROUND TASKS - ---- (GROUND) Fire at a VEC2 point until ammunition is finished. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 The point to fire at. --- @param Dcs.DCSTypes#Distance Radius The radius of the zone to deploy the fire at. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius ) - self:F2( { self.ControllableName, Vec2, Radius } ) - - -- FireAtPoint = { - -- id = 'FireAtPoint', - -- params = { - -- point = Vec2, - -- radius = Distance, - -- } - -- } - - local DCSTask - DCSTask = { id = 'FireAtPoint', - params = { - point = Vec2, - radius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Hold ground controllable from moving. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskHold() - self:F2( { self.ControllableName } ) - --- Hold = { --- id = 'Hold', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Hold', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- TASKS FOR AIRBORNE AND GROUND UNITS/CONTROLLABLES - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. --- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, Designation, Datalink } ) - --- FAC_AttackControllable = { --- id = 'FAC_AttackControllable', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_AttackControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - --- EN-ACT_ROUTE TASKS FOR AIRBORNE CONTROLLABLES - ---- (AIR) Engaging targets of defined types. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Distance Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. --- @param #number Priority All enroute tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) - self:F2( { self.ControllableName, Distance, TargetTypes, Priority } ) - --- EngageTargets ={ --- id = 'EngageTargets', --- params = { --- maxDist = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargets', - params = { - maxDist = Distance, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR) Engaging a targets of defined types at circle-shaped zone. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the zone. --- @param Dcs.DCSTypes#Distance Radius Radius of the zone. --- @param Dcs.DCSTypes#AttributeNameArray TargetTypes Array of target categories allowed to engage. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageTargets( Vec2, Radius, TargetTypes, Priority ) - self:F2( { self.ControllableName, Vec2, Radius, TargetTypes, Priority } ) - --- EngageTargetsInZone = { --- id = 'EngageTargetsInZone', --- params = { --- point = Vec2, --- zoneRadius = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargetsInZone', - params = { - point = Vec2, - zoneRadius = Radius, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param Dcs.DCSTypes#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.ControllableName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- EngageControllable = { - -- id = 'EngageControllable ', - -- params = { - -- groupId = Group.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend, - -- attackQty = number, - -- directionEnabled = boolean, - -- direction = Azimuth, - -- altitudeEnabled = boolean, - -- altitude = Distance, - -- attackQtyLimit = boolean, - -- priority = number, - -- } - -- } - - local DirectionEnabled = nil - if Direction then - DirectionEnabled = true - end - - local AltitudeEnabled = nil - if Altitude then - AltitudeEnabled = true - end - - local DCSTask - DCSTask = { id = 'EngageControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - directionEnabled = DirectionEnabled, - direction = Direction, - altitudeEnabled = AltitudeEnabled, - altitude = Altitude, - attackQtyLimit = AttackQtyLimit, - priority = Priority, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Attack the Unit. --- @param #CONTROLLABLE self --- @param Wrapper.Unit#UNIT AttackUnit The UNIT. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. --- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackControllable" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEngageUnit( AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack ) - self:F2( { self.ControllableName, AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, ControllableAttack } ) - - -- EngageUnit = { - -- id = 'EngageUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- controllableAttack = boolean, - -- priority = number, - -- } - -- } - - local DCSTask - DCSTask = { id = 'EngageUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - controllableAttack = ControllableAttack, - priority = Priority, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskAWACS( ) - self:F2( { self.ControllableName } ) - --- AWACS = { --- id = 'AWACS', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'AWACS', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskTanker( ) - self:F2( { self.ControllableName } ) - --- Tanker = { --- id = 'Tanker', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Tanker', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for ground units/controllables - ---- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. --- @param #CONTROLLABLE self --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskEWR( ) - self:F2( { self.ControllableName } ) - --- EWR = { --- id = 'EWR', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'EWR', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for airborne and ground units/controllables - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Wrapper.Controllable#CONTROLLABLE AttackGroup Target CONTROLLABLE. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param Dcs.DCSTypes#AI.Task.Designation Designation (optional) Designation type. --- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) - self:F2( { self.ControllableName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) - --- FAC_EngageControllable = { --- id = 'FAC_EngageControllable', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean, --- priority = number, --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_EngageControllable', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - priority = Priority, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the controllable lead unit will be a FAC. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Distance Radius The maximal distance from the FAC to a target. --- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority ) - self:F2( { self.ControllableName, Radius, Priority } ) - --- FAC = { --- id = 'FAC', --- params = { --- radius = Distance, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'FAC', - params = { - radius = Radius, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - - ---- (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. --- @param #number Duration The duration in seconds to wait. --- @param #CONTROLLABLE EmbarkingControllable The controllable to be embarked. --- @return Dcs.DCSTasking.Task#Task The DCS task structure -function CONTROLLABLE:TaskEmbarking( Point, Duration, EmbarkingControllable ) - self:F2( { self.ControllableName, Point, Duration, EmbarkingControllable.DCSControllable } ) - - local DCSTask - DCSTask = { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - controllablesForEmbarking = { EmbarkingControllable.ControllableID }, - durationFlag = true, - distributionFlag = false, - distribution = {}, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Embark to a Transport landed at a location. - ---- Move to a defined Vec2 Point, and embark to a controllable when arrived within a defined Radius. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec2 Point The point where to wait. --- @param #number Radius The radius of the embarking zone around the Point. --- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) - self:F2( { self.ControllableName, Point, Radius } ) - - local DCSTask --Dcs.DCSTasking.Task#Task - DCSTask = { id = 'EmbarkToTransport', - params = { x = Point.x, - y = Point.y, - zoneRadius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - - ---- (AIR + GROUND) Return a mission task from a mission template. --- @param #CONTROLLABLE self --- @param #table TaskMission A table containing the mission task. --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskMission( TaskMission ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { TaskMission, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- Return a Misson task to follow a given route defined by Points. --- @param #CONTROLLABLE self --- @param #table Points A table of route points. --- @return Dcs.DCSTasking.Task#Task -function CONTROLLABLE:TaskRoute( Points ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR + GROUND) Make the Controllable move to fly to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskRouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllablePoint = self:GetUnit( 1 ):GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.y - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - ---- (AIR + GROUND) Make the Controllable move to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:TaskRouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllableVec3 = self:GetUnit( 1 ):GetVec3() - - local PointFrom = {} - PointFrom.x = ControllableVec3.x - PointFrom.y = ControllableVec3.z - PointFrom.alt = ControllableVec3.y - PointFrom.alt_type = "BARO" - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.z - PointTo.alt = Point.y - PointTo.alt_type = "BARO" - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - - - ---- Make the controllable to follow a given route. --- @param #CONTROLLABLE self --- @param #table GoPoints A table of Route Points. --- @return #CONTROLLABLE self -function CONTROLLABLE:Route( GoPoints ) - self:F2( GoPoints ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - local Points = routines.utils.deepCopy( GoPoints ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } - local Controller = self:_GetController() - --Controller.setTask( Controller, MissionTask ) - self.TaskScheduler:Schedule( Controller, Controller.setTask, { MissionTask }, 1 ) - return self - end - - return nil -end - - - ---- (AIR + GROUND) Route the controllable to a given zone. --- The controllable final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to route to. --- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Cone" - PointFrom.speed = 20 / 1.6 - - - local PointTo = {} - local ZonePoint - - if Randomize then - ZonePoint = Zone:GetRandomVec2() - else - ZonePoint = Zone:GetVec2() - end - - PointTo.x = ZonePoint.x - PointTo.y = ZonePoint.y - PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 20 / 1.6 - end - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self - end - - return nil -end - ---- (AIR) Return the Controllable to an @{Wrapper.Airbase#AIRBASE} --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Wrapper.Airbase#AIRBASE ReturnAirbase The @{Wrapper.Airbase#AIRBASE} to return to. --- @param #number Speed (optional) The speed. --- @return #string The route -function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed ) - self:F2( { ReturnAirbase, Speed } ) - --- Example --- [4] = --- { --- ["alt"] = 45, --- ["type"] = "Land", --- ["action"] = "Landing", --- ["alt_type"] = "BARO", --- ["formation_template"] = "", --- ["properties"] = --- { --- ["vnav"] = 1, --- ["scale"] = 0, --- ["angle"] = 0, --- ["vangle"] = 0, --- ["steer"] = 2, --- }, -- end of ["properties"] --- ["ETA"] = 527.81058817743, --- ["airdromeId"] = 12, --- ["y"] = 243127.2973737, --- ["x"] = -5406.2803440839, --- ["name"] = "DictKey_WptName_53", --- ["speed"] = 138.88888888889, --- ["ETA_locked"] = false, --- ["task"] = --- { --- ["id"] = "ComboTask", --- ["params"] = --- { --- ["tasks"] = --- { --- }, -- end of ["tasks"] --- }, -- end of ["params"] --- }, -- end of ["task"] --- ["speed_locked"] = true, --- }, -- end of [4] - - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - local ControllableVelocity = self:GetMaxVelocity() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = ControllableVelocity - - - local PointTo = {} - local AirbasePoint = ReturnAirbase:GetVec2() - - PointTo.x = AirbasePoint.x - PointTo.y = AirbasePoint.y - PointTo.type = "Land" - PointTo.action = "Landing" - PointTo.airdromeId = ReturnAirbase:GetID()-- Airdrome ID - self:T(PointTo.airdromeId) - --PointTo.alt = 0 - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - local Route = { points = Points, } - - return Route - end - - return nil -end - --- Commands - ---- Do Script command --- @param #CONTROLLABLE self --- @param #string DoScript --- @return #DCSCommand -function CONTROLLABLE:CommandDoScript( DoScript ) - - local DCSDoScript = { - id = "Script", - params = { - command = DoScript, - }, - } - - self:T3( DCSDoScript ) - return DCSDoScript -end - - ---- Return the mission template of the controllable. --- @param #CONTROLLABLE self --- @return #table The MissionTemplate --- TODO: Rework the method how to retrieve a template ... -function CONTROLLABLE:GetTaskMission() - self:F2( self.ControllableName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template ) -end - ---- Return the mission route of the controllable. --- @param #CONTROLLABLE self --- @return #table The mission route defined by points. -function CONTROLLABLE:GetTaskRoute() - self:F2( self.ControllableName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template.route.points ) -end - ---- Return the route of a controllable by using the @{Core.Database#DATABASE} class. --- @param #CONTROLLABLE self --- @param #number Begin The route point from where the copy will start. The base route point is 0. --- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. --- @param #boolean Randomize Randomization of the route, when true. --- @param #number Radius When randomization is on, the randomization is within the radius. -function CONTROLLABLE:CopyRoute( Begin, End, Randomize, Radius ) - self:F2( { Begin, End } ) - - local Points = {} - - -- Could be a Spawned Controllable - local ControllableName = string.match( self:GetName(), ".*#" ) - if ControllableName then - ControllableName = ControllableName:sub( 1, -2 ) - else - ControllableName = self:GetName() - end - - self:T3( { ControllableName } ) - - local Template = _DATABASE.Templates.Controllables[ControllableName].Template - - if Template then - if not Begin then - Begin = 0 - end - if not End then - End = 0 - end - - for TPointID = Begin + 1, #Template.route.points - End do - if Template.route.points[TPointID] then - Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) - if Randomize then - if not Radius then - Radius = 500 - end - Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) - Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) - end - end - end - return Points - else - error( "Template not found for Controllable : " .. ControllableName ) - end - - return nil -end - - ---- Return the detected targets of the controllable. --- The optional parametes specify the detection methods that can be applied. --- If no detection method is given, the detection will use all the available methods by default. --- @param Wrapper.Controllable#CONTROLLABLE self --- @param #boolean DetectVisual (optional) --- @param #boolean DetectOptical (optional) --- @param #boolean DetectRadar (optional) --- @param #boolean DetectIRST (optional) --- @param #boolean DetectRWR (optional) --- @param #boolean DetectDLINK (optional) --- @return #table DetectedTargets -function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK ) - self:F2( self.ControllableName ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local DetectionVisual = ( DetectVisual and DetectVisual == true ) and Controller.Detection.VISUAL or nil - local DetectionOptical = ( DetectOptical and DetectOptical == true ) and Controller.Detection.OPTICAL or nil - local DetectionRadar = ( DetectRadar and DetectRadar == true ) and Controller.Detection.RADAR or nil - local DetectionIRST = ( DetectIRST and DetectIRST == true ) and Controller.Detection.IRST or nil - local DetectionRWR = ( DetectRWR and DetectRWR == true ) and Controller.Detection.RWR or nil - local DetectionDLINK = ( DetectDLINK and DetectDLINK == true ) and Controller.Detection.DLINK or nil - - - return self:_GetController():getDetectedTargets( DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK ) - end - - return nil -end - -function CONTROLLABLE:IsTargetDetected( DCSObject ) - self:F2( self.ControllableName ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - - local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity - = self:_GetController().isTargetDetected( self:_GetController(), DCSObject, - Controller.Detection.VISUAL, - Controller.Detection.OPTIC, - Controller.Detection.RADAR, - Controller.Detection.IRST, - Controller.Detection.RWR, - Controller.Detection.DLINK - ) - return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity - end - - return nil -end - --- Options - ---- Can the CONTROLLABLE hold their weapons? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEHoldFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Holding weapons. --- @param Wrapper.Controllable#CONTROLLABLE self --- @return Wrapper.Controllable#CONTROLLABLE self -function CONTROLLABLE:OptionROEHoldFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.WEAPON_HOLD ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.WEAPON_HOLD ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack returning on enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEReturnFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Return fire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEReturnFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.RETURN_FIRE ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.RETURN_FIRE ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.RETURN_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack designated targets? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEOpenFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Openfire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEOpenFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.OPEN_FIRE ) - elseif self:IsGround() then - Controller:setOption( AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.OPEN_FIRE ) - elseif self:IsShip() then - Controller:setOption( AI.Option.Naval.id.ROE, AI.Option.Naval.val.ROE.OPEN_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE attack targets of opportunity? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROEWeaponFreePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Weapon free. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROEWeaponFree() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE ignore enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTNoReactionPossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- No evasion on enemy threats. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTNoReaction() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade using passive defenses? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTPassiveDefensePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Evasion passive defense. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTPassiveDefense() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.PASSIVE_DEFENCE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade on enemy fire? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTEvadeFirePossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTEvadeFire() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE ) - end - - return self - end - - return nil -end - ---- Can the CONTROLLABLE evade on fire using vertical manoeuvres? --- @param #CONTROLLABLE self --- @return #boolean -function CONTROLLABLE:OptionROTVerticalPossible() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire using vertical manoeuvres. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE self -function CONTROLLABLE:OptionROTVertical() - self:F2( { self.ControllableName } ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local Controller = self:_GetController() - - if self:IsAir() then - Controller:setOption( AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.BYPASS_AND_ESCAPE ) - end - - return self - end - - return nil -end - ---- Retrieve the controllable mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Wrapper.Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. --- Use the method @{Controllable@CONTROLLABLE:WayPointExecute) to start the execution of the new mission plan. --- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED! --- @param #CONTROLLABLE self --- @param #table WayPoints If WayPoints is given, then use the route. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointInitialize( WayPoints ) - self:F( { WayPoints } ) - - if WayPoints then - self.WayPoints = WayPoints - else - self.WayPoints = self:GetTaskRoute() - end - - return self -end - ---- Get the current WayPoints set with the WayPoint functions( Note that the WayPoints can be nil, although there ARE waypoints). --- @param #CONTROLLABLE self --- @return #table WayPoints If WayPoints is given, then return the WayPoints structure. -function CONTROLLABLE:GetWayPoints() - self:F( ) - - if self.WayPoints then - return self.WayPoints - end - - return nil -end - ---- Registers a waypoint function that will be executed when the controllable moves over the WayPoint. --- @param #CONTROLLABLE self --- @param #number WayPoint The waypoint number. Note that the start waypoint on the route is WayPoint 1! --- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions. --- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... ) - self:F2( { WayPoint, WayPointIndex, WayPointFunction } ) - - table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex ) - self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPoint, WayPointIndex, WayPointFunction, arg ) - return self -end - - -function CONTROLLABLE:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) - self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) - - local DCSTask - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) " - - if FunctionArguments and #FunctionArguments > 0 then - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, " .. table.concat( FunctionArguments, "," ) .. ")" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )" - end - - DCSTask = self:TaskWrappedAction( - self:CommandDoScript( - table.concat( DCSScript ) - ), WayPointIndex - ) - - self:T3( DCSTask ) - - return DCSTask - -end - ---- Executes the WayPoint plan. --- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint. --- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1! --- @param #CONTROLLABLE self --- @param #number WayPoint The WayPoint from where to execute the mission. --- @param #number WaitTime The amount seconds to wait before initiating the mission. --- @return #CONTROLLABLE -function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime ) - self:F( { WayPoint, WaitTime } ) - - if not WayPoint then - WayPoint = 1 - end - - -- When starting the mission from a certain point, the TaskPoints need to be deleted before the given WayPoint. - for TaskPointID = 1, WayPoint - 1 do - table.remove( self.WayPoints, 1 ) - end - - self:T3( self.WayPoints ) - - self:SetTask( self:TaskRoute( self.WayPoints ), WaitTime ) - - return self -end - --- Message APIs - - ---- This module contains the GROUP class. --- --- 1) @{Wrapper.Group#GROUP} class, extends @{Wrapper.Controllable#CONTROLLABLE} --- ============================================================= --- The @{Wrapper.Group#GROUP} class is a wrapper class to handle the DCS Group objects: --- --- * Support all DCS Group APIs. --- * Enhance with Group specific APIs not in the DCS Group API set. --- * Handle local Group Controller. --- * Manage the "state" of the DCS Group. --- --- **IMPORTANT: ONE SHOULD NEVER SANATIZE these GROUP OBJECT REFERENCES! (make the GROUP object references nil).** --- --- 1.1) GROUP reference methods --- ----------------------- --- For each DCS Group object alive within a running mission, a GROUP wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Group objects are spawned (using the @{SPAWN} class). --- --- The GROUP class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the DCS Group or the DCS GroupName. --- --- Another thing to know is that GROUP objects do not "contain" the DCS Group object. --- The GROUP methods will reference the DCS Group object by name when it is needed during API execution. --- If the DCS Group object does not exist or is nil, the GROUP methods will return nil and log an exception in the DCS.log file. --- --- The GROUP class provides the following functions to retrieve quickly the relevant GROUP instance: --- --- * @{#GROUP.Find}(): Find a GROUP instance from the _DATABASE object using a DCS Group object. --- * @{#GROUP.FindByName}(): Find a GROUP instance from the _DATABASE object using a DCS Group name. --- --- 1.2) GROUP task methods --- ----------------------- --- Several group task methods are available that help you to prepare tasks. --- These methods return a string consisting of the task description, which can then be given to either a --- @{Wrapper.Controllable#CONTROLLABLE.PushTask} or @{Wrapper.Controllable#CONTROLLABLE.SetTask} method to assign the task to the GROUP. --- Tasks are specific for the category of the GROUP, more specific, for AIR, GROUND or AIR and GROUND. --- Each task description where applicable indicates for which group category the task is valid. --- There are 2 main subdivisions of tasks: Assigned tasks and EnRoute tasks. --- --- ### 1.2.1) Assigned task methods --- --- Assigned task methods make the group execute the task where the location of the (possible) targets of the task are known before being detected. --- This is different from the EnRoute tasks, where the targets of the task need to be detected before the task can be executed. --- --- Find below a list of the **assigned task** methods: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackGroup}: (AIR) Attack a Group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackMapObject}: (AIR) Attacking the map object (building, structure, e.t.c). --- * @{Wrapper.Controllable#CONTROLLABLE.TaskAttackUnit}: (AIR) Attack the Unit. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskBombing}: (Wrapper.Controllable#CONTROLLABLEDelivering weapon at the point on the ground. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskBombingRunway}: (AIR) Delivering weapon on the runway. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEmbarking}: (AIR) Move the group to a Vec2 Point, wait for a defined duration and embark a group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFAC_AttackGroup}: (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire at a VEC2 point until ammunition is finished. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskHold}: (GROUND) Hold ground group from moving. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the group. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the group at a @{Core.Zone#ZONE_RADIUS). --- * @{Wrapper.Controllable#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the group at a specified alititude. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Group move to a given point. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Group move to a given point. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the group to a given zone. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskReturnToBase}: (AIR) Route the group to an airbase. --- --- ### 1.2.2) EnRoute task methods --- --- EnRoute tasks require the targets of the task need to be detected by the group (using its sensors) before the task can be executed: --- --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskAWACS}: (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEngageGroup}: (AIR) Engaging a group. The task does not assign the target group to the unit/group to attack now; it just allows the unit/group to engage the target group as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEngageTargets}: (AIR) Engaging targets of defined types. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskEWR}: (AIR) Attack the Unit. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskFAC}: (AIR + GROUND) The task makes the group/unit a FAC and lets the FAC to choose a targets (enemy ground group) around as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskFAC_EngageGroup}: (AIR + GROUND) The task makes the group/unit a FAC and lets the FAC to choose the target (enemy ground group) as well as other assigned targets. --- * @{Wrapper.Controllable#CONTROLLABLE.EnRouteTaskTanker}: (AIR) Aircraft will act as a tanker for friendly units. No parameters. --- --- ### 1.2.3) Preparation task methods --- --- There are certain task methods that allow to tailor the task behaviour: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task. --- * @{Wrapper.Controllable#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition. --- --- ### 1.2.4) Obtain the mission from group templates --- --- Group templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a group and assign it to another: --- --- * @{Wrapper.Controllable#CONTROLLABLE.TaskMission}: (AIR + GROUND) Return a mission task from a mission template. --- --- 1.3) GROUP Command methods --- -------------------------- --- Group **command methods** prepare the execution of commands using the @{Wrapper.Controllable#CONTROLLABLE.SetCommand} method: --- --- * @{Wrapper.Controllable#CONTROLLABLE.CommandDoScript}: Do Script command. --- * @{Wrapper.Controllable#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command. --- --- 1.4) GROUP Option methods --- ------------------------- --- Group **Option methods** change the behaviour of the Group while being alive. --- --- ### 1.4.1) Rule of Engagement: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEWeaponFree} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEOpenFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEReturnFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEEvadeFire} --- --- To check whether an ROE option is valid for a specific group, use: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEWeaponFreePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEOpenFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEReturnFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROEEvadeFirePossible} --- --- ### 1.4.2) Rule on thread: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTNoReaction} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTPassiveDefense} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTEvadeFire} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTVertical} --- --- To test whether an ROT option is valid for a specific group, use: --- --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTNoReactionPossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTPassiveDefensePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTEvadeFirePossible} --- * @{Wrapper.Controllable#CONTROLLABLE.OptionROTVerticalPossible} --- --- 1.5) GROUP Zone validation methods --- ---------------------------------- --- The group can be validated whether it is completely, partly or not within a @{Zone}. --- Use the following Zone validation methods on the group: --- --- * @{#GROUP.IsCompletelyInZone}: Returns true if all units of the group are within a @{Zone}. --- * @{#GROUP.IsPartlyInZone}: Returns true if some units of the group are within a @{Zone}. --- * @{#GROUP.IsNotInZone}: Returns true if none of the group units of the group are within a @{Zone}. --- --- The zone can be of any @{Zone} class derived from @{Core.Zone#ZONE_BASE}. So, these methods are polymorphic to the zones tested on. --- --- @module Group --- @author FlightControl - ---- The GROUP class --- @type GROUP --- @extends Wrapper.Controllable#CONTROLLABLE --- @field #string GroupName The name of the group. -GROUP = { - ClassName = "GROUP", -} - ---- Create a new GROUP from a DCSGroup --- @param #GROUP self --- @param Dcs.DCSWrapper.Group#Group GroupName The DCS Group name --- @return #GROUP self -function GROUP:Register( GroupName ) - local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) - self:F2( GroupName ) - self.GroupName = GroupName - return self -end - --- Reference methods. - ---- Find the GROUP wrapper class instance using the DCS Group. --- @param #GROUP self --- @param Dcs.DCSWrapper.Group#Group DCSGroup The DCS Group. --- @return #GROUP The GROUP. -function GROUP:Find( DCSGroup ) - - local GroupName = DCSGroup:getName() -- Wrapper.Group#GROUP - local GroupFound = _DATABASE:FindGroup( GroupName ) - return GroupFound -end - ---- Find the created GROUP using the DCS Group Name. --- @param #GROUP self --- @param #string GroupName The DCS Group Name. --- @return #GROUP The GROUP. -function GROUP:FindByName( GroupName ) - - local GroupFound = _DATABASE:FindGroup( GroupName ) - return GroupFound -end - --- DCS Group methods support. - ---- Returns the DCS Group. --- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group The DCS Group. -function GROUP:GetDCSObject() - local DCSGroup = Group.getByName( self.GroupName ) - - if DCSGroup then - return DCSGroup - end - - return nil -end - - ---- Returns if the DCS Group is alive. --- When the group exists at run-time, this method will return true, otherwise false. --- @param #GROUP self --- @return #boolean true if the DCS Group is alive. -function GROUP:IsAlive() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupIsAlive = DCSGroup:isExist() - self:T3( GroupIsAlive ) - return GroupIsAlive - end - - return nil -end - ---- Destroys the DCS Group and all of its DCS Units. --- Note that this destroy method also raises a destroy event at run-time. --- So all event listeners will catch the destroy event of this DCS Group. --- @param #GROUP self -function GROUP:Destroy() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - self:CreateEventCrash( timer.getTime(), UnitData ) - end - DCSGroup:destroy() - DCSGroup = nil - end - - return nil -end - ---- Returns category of the DCS Group. --- @param #GROUP self --- @return Dcs.DCSWrapper.Group#Group.Category The category ID -function GROUP:GetCategory() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T3( GroupCategory ) - return GroupCategory - end - - return nil -end - ---- Returns the category name of the DCS Group. --- @param #GROUP self --- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship -function GROUP:GetCategoryName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local CategoryNames = { - [Group.Category.AIRPLANE] = "Airplane", - [Group.Category.HELICOPTER] = "Helicopter", - [Group.Category.GROUND] = "Ground Unit", - [Group.Category.SHIP] = "Ship", - } - local GroupCategory = DCSGroup:getCategory() - self:T3( GroupCategory ) - - return CategoryNames[GroupCategory] - end - - return nil -end - - ---- Returns the coalition of the DCS Group. --- @param #GROUP self --- @return Dcs.DCSCoalitionWrapper.Object#coalition.side The coalition side of the DCS Group. -function GROUP:GetCoalition() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCoalition = DCSGroup:getCoalition() - self:T3( GroupCoalition ) - return GroupCoalition - end - - return nil -end - ---- Returns the country of the DCS Group. --- @param #GROUP self --- @return Dcs.DCScountry#country.id The country identifier. --- @return #nil The DCS Group is not existing or alive. -function GROUP:GetCountry() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - if DCSGroup then - local GroupCountry = DCSGroup:getUnit(1):getCountry() - self:T3( GroupCountry ) - return GroupCountry - end - - return nil -end - ---- Returns the UNIT wrapper class with number UnitNumber. --- If the underlying DCS Unit does not exist, the method will return nil. . --- @param #GROUP self --- @param #number UnitNumber The number of the UNIT wrapper class to be returned. --- @return Wrapper.Unit#UNIT The UNIT wrapper class. -function GROUP:GetUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) - self:T3( UnitFound.UnitName ) - self:T2( UnitFound ) - return UnitFound - end - - return nil -end - ---- Returns the DCS Unit with number UnitNumber. --- If the underlying DCS Unit does not exist, the method will return nil. . --- @param #GROUP self --- @param #number UnitNumber The number of the DCS Unit to be returned. --- @return Dcs.DCSWrapper.Unit#Unit The DCS Unit. -function GROUP:GetDCSUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) - self:T3( DCSUnitFound ) - return DCSUnitFound - end - - return nil -end - ---- Returns current size of the DCS Group. --- If some of the DCS Units of the DCS Group are destroyed the size of the DCS Group is changed. --- @param #GROUP self --- @return #number The DCS Group size. -function GROUP:GetSize() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupSize = DCSGroup:getSize() - self:T3( GroupSize ) - return GroupSize - end - - return nil -end - ---- ---- Returns the initial size of the DCS Group. --- If some of the DCS Units of the DCS Group are destroyed, the initial size of the DCS Group is unchanged. --- @param #GROUP self --- @return #number The DCS Group initial size. -function GROUP:GetInitialSize() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupInitialSize = DCSGroup:getInitialSize() - self:T3( GroupInitialSize ) - return GroupInitialSize - end - - return nil -end - ---- Returns the UNITs wrappers of the DCS Units of the DCS Group. --- @param #GROUP self --- @return #table The UNITs wrappers. -function GROUP:GetUnits() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnits = DCSGroup:getUnits() - local Units = {} - for Index, UnitData in pairs( DCSUnits ) do - Units[#Units+1] = UNIT:Find( UnitData ) - end - self:T3( Units ) - return Units - end - - return nil -end - - ---- Returns the DCS Units of the DCS Group. --- @param #GROUP self --- @return #table The DCS Units. -function GROUP:GetDCSUnits() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local DCSUnits = DCSGroup:getUnits() - self:T3( DCSUnits ) - return DCSUnits - end - - return nil -end - - ---- Activates a GROUP. --- @param #GROUP self -function GROUP:Activate() - self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSObject() ) - return self:GetDCSObject() -end - - ---- Gets the type name of the group. --- @param #GROUP self --- @return #string The type name of the group. -function GROUP:GetTypeName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupTypeName = DCSGroup:getUnit(1):getTypeName() - self:T3( GroupTypeName ) - return( GroupTypeName ) - end - - return nil -end - ---- Gets the CallSign of the first DCS Unit of the DCS Group. --- @param #GROUP self --- @return #string The CallSign of the first DCS Unit of the DCS Group. -function GROUP:GetCallsign() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCallSign = DCSGroup:getUnit(1):getCallsign() - self:T3( GroupCallSign ) - return GroupCallSign - end - - return nil -end - ---- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. --- @param #GROUP self --- @return Dcs.DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. -function GROUP:GetVec2() - self:F2( self.GroupName ) - - local UnitPoint = self:GetUnit(1) - UnitPoint:GetVec2() - local GroupPointVec2 = UnitPoint:GetVec2() - self:T3( GroupPointVec2 ) - return GroupPointVec2 -end - ---- Returns the current Vec3 vector of the first DCS Unit in the GROUP. --- @return Dcs.DCSTypes#Vec3 Current Vec3 of the first DCS Unit of the GROUP. -function GROUP:GetVec3() - self:F2( self.GroupName ) - - local GroupVec3 = self:GetUnit(1):GetVec3() - self:T3( GroupVec3 ) - return GroupVec3 -end - - - --- Is Zone Functions - ---- Returns true if all units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsCompletelyInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - -- TODO: Rename IsPointVec3InZone to IsVec3InZone - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - else - return false - end - end - - return true -end - ---- Returns true if some units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsPartlyInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - return true - end - end - - return false -end - ---- Returns true if none of the group units of the group are within a @{Zone}. --- @param #GROUP self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the Group is completely within the @{Core.Zone#ZONE_BASE} -function GROUP:IsNotInZone( Zone ) - self:F2( { self.GroupName, Zone } ) - - for UnitID, UnitData in pairs( self:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsPointVec3InZone( Unit:GetVec3() ) then - return false - end - end - - return true -end - ---- Returns if the group is of an air category. --- If the group is a helicopter or a plane, then this method will return true, otherwise false. --- @param #GROUP self --- @return #boolean Air category evaluation result. -function GROUP:IsAir() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER - self:T3( IsAirResult ) - return IsAirResult - end - - return nil -end - ---- Returns if the DCS Group contains Helicopters. --- @param #GROUP self --- @return #boolean true if DCS Group contains Helicopters. -function GROUP:IsHelicopter() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.HELICOPTER - end - - return nil -end - ---- Returns if the DCS Group contains AirPlanes. --- @param #GROUP self --- @return #boolean true if DCS Group contains AirPlanes. -function GROUP:IsAirPlane() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.AIRPLANE - end - - return nil -end - ---- Returns if the DCS Group contains Ground troops. --- @param #GROUP self --- @return #boolean true if DCS Group contains Ground troops. -function GROUP:IsGround() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.GROUND - end - - return nil -end - ---- Returns if the DCS Group contains Ships. --- @param #GROUP self --- @return #boolean true if DCS Group contains Ships. -function GROUP:IsShip() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupCategory = DCSGroup:getCategory() - self:T2( GroupCategory ) - return GroupCategory == Group.Category.SHIP - end - - return nil -end - ---- Returns if all units of the group are on the ground or landed. --- If all units of this group are on the ground, this function will return true, otherwise false. --- @param #GROUP self --- @return #boolean All units on the ground result. -function GROUP:AllOnGround() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local AllOnGroundResult = true - - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - if UnitData:inAir() then - AllOnGroundResult = false - end - end - - self:T3( AllOnGroundResult ) - return AllOnGroundResult - end - - return nil -end - ---- Returns the current maximum velocity of the group. --- Each unit within the group gets evaluated, and the maximum velocity (= the unit which is going the fastest) is returned. --- @param #GROUP self --- @return #number Maximum velocity found. -function GROUP:GetMaxVelocity() - self:F2() - - local DCSGroup = self:GetDCSObject() - - if DCSGroup then - local GroupVelocityMax = 0 - - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - - local UnitVelocityVec3 = UnitData:getVelocity() - local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) - - if UnitVelocity > GroupVelocityMax then - GroupVelocityMax = UnitVelocity - end - end - - return GroupVelocityMax - end - - return nil -end - ---- Returns the current minimum height of the group. --- Each unit within the group gets evaluated, and the minimum height (= the unit which is the lowest elevated) is returned. --- @param #GROUP self --- @return #number Minimum height found. -function GROUP:GetMinHeight() - self:F2() - -end - ---- Returns the current maximum height of the group. --- Each unit within the group gets evaluated, and the maximum height (= the unit which is the highest elevated) is returned. --- @param #GROUP self --- @return #number Maximum height found. -function GROUP:GetMaxHeight() - self:F2() - -end - --- SPAWNING - ---- Respawn the @{GROUP} using a (tweaked) template of the Group. --- The template must be retrieved with the @{Wrapper.Group#GROUP.GetTemplate}() function. --- The template contains all the definitions as declared within the mission file. --- To understand templates, do the following: --- --- * unpack your .miz file into a directory using 7-zip. --- * browse in the directory created to the file **mission**. --- * open the file and search for the country group definitions. --- --- Your group template will contain the fields as described within the mission file. --- --- This function will: --- --- * Get the current position and heading of the group. --- * When the group is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. --- * Then it will destroy the current alive group. --- * And it will respawn the group using your new template definition. --- @param Wrapper.Group#GROUP self --- @param #table Template The template of the Group retrieved with GROUP:GetTemplate() -function GROUP:Respawn( Template ) - - local Vec3 = self:GetVec3() - Template.x = Vec3.x - Template.y = Vec3.z - --Template.x = nil - --Template.y = nil - - self:E( #Template.units ) - for UnitID, UnitData in pairs( self:GetUnits() ) do - local GroupUnit = UnitData -- Wrapper.Unit#UNIT - self:E( GroupUnit:GetName() ) - if GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - Template.units[UnitID].alt = GroupUnitVec3.y - Template.units[UnitID].x = GroupUnitVec3.x - Template.units[UnitID].y = GroupUnitVec3.z - Template.units[UnitID].heading = GroupUnitHeading - self:E( { UnitID, Template.units[UnitID], Template.units[UnitID] } ) - end - end - - self:Destroy() - _DATABASE:Spawn( Template ) -end - ---- Returns the group template from the @{DATABASE} (_DATABASE object). --- @param #GROUP self --- @return #table -function GROUP:GetTemplate() - local GroupName = self:GetName() - self:E( GroupName ) - return _DATABASE:GetGroupTemplate( GroupName ) -end - ---- Sets the controlled status in a Template. --- @param #GROUP self --- @param #boolean Controlled true is controlled, false is uncontrolled. --- @return #table -function GROUP:SetTemplateControlled( Template, Controlled ) - Template.uncontrolled = not Controlled - return Template -end - ---- Sets the CountryID of the group in a Template. --- @param #GROUP self --- @param Dcs.DCScountry#country.id CountryID The country ID. --- @return #table -function GROUP:SetTemplateCountry( Template, CountryID ) - Template.CountryID = CountryID - return Template -end - ---- Sets the CoalitionID of the group in a Template. --- @param #GROUP self --- @param Dcs.DCSCoalitionWrapper.Object#coalition.side CoalitionID The coalition ID. --- @return #table -function GROUP:SetTemplateCoalition( Template, CoalitionID ) - Template.CoalitionID = CoalitionID - return Template -end - - - - ---- Return the mission template of the group. --- @param #GROUP self --- @return #table The MissionTemplate -function GROUP:GetTaskMission() - self:F2( self.GroupName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template ) -end - ---- Return the mission route of the group. --- @param #GROUP self --- @return #table The mission route defined by points. -function GROUP:GetTaskRoute() - self:F2( self.GroupName ) - - return routines.utils.deepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points ) -end - ---- Return the route of a group by using the @{Core.Database#DATABASE} class. --- @param #GROUP self --- @param #number Begin The route point from where the copy will start. The base route point is 0. --- @param #number End The route point where the copy will end. The End point is the last point - the End point. The last point has base 0. --- @param #boolean Randomize Randomization of the route, when true. --- @param #number Radius When randomization is on, the randomization is within the radius. -function GROUP:CopyRoute( Begin, End, Randomize, Radius ) - self:F2( { Begin, End } ) - - local Points = {} - - -- Could be a Spawned Group - local GroupName = string.match( self:GetName(), ".*#" ) - if GroupName then - GroupName = GroupName:sub( 1, -2 ) - else - GroupName = self:GetName() - end - - self:T3( { GroupName } ) - - local Template = _DATABASE.Templates.Groups[GroupName].Template - - if Template then - if not Begin then - Begin = 0 - end - if not End then - End = 0 - end - - for TPointID = Begin + 1, #Template.route.points - End do - if Template.route.points[TPointID] then - Points[#Points+1] = routines.utils.deepCopy( Template.route.points[TPointID] ) - if Randomize then - if not Radius then - Radius = 500 - end - Points[#Points].x = Points[#Points].x + math.random( Radius * -1, Radius ) - Points[#Points].y = Points[#Points].y + math.random( Radius * -1, Radius ) - end - end - end - return Points - else - error( "Template not found for Group : " .. GroupName ) - end - - return nil -end - ---- Calculate the maxium A2G threat level of the Group. --- @param #GROUP self -function GROUP:CalculateThreatLevelA2G() - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( self:GetUnits() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - return MaxThreatLevelA2G -end - - ---- This module contains the UNIT class. --- --- 1) @{#UNIT} class, extends @{Wrapper.Controllable#CONTROLLABLE} --- =========================================================== --- The @{#UNIT} class is a wrapper class to handle the DCS Unit objects: --- --- * Support all DCS Unit APIs. --- * Enhance with Unit specific APIs not in the DCS Unit API set. --- * Handle local Unit Controller. --- * Manage the "state" of the DCS Unit. --- --- --- 1.1) UNIT reference methods --- ---------------------- --- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts), and dynamically when new DCS Unit objects are spawned (using the @{SPAWN} class). --- --- The UNIT class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference --- using the DCS Unit or the DCS UnitName. --- --- Another thing to know is that UNIT objects do not "contain" the DCS Unit object. --- The UNIT methods will reference the DCS Unit object by name when it is needed during API execution. --- If the DCS Unit object does not exist or is nil, the UNIT methods will return nil and log an exception in the DCS.log file. --- --- The UNIT class provides the following functions to retrieve quickly the relevant UNIT instance: --- --- * @{#UNIT.Find}(): Find a UNIT instance from the _DATABASE object using a DCS Unit object. --- * @{#UNIT.FindByName}(): Find a UNIT instance from the _DATABASE object using a DCS Unit name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these UNIT OBJECT REFERENCES! (make the UNIT object references nil). --- --- 1.2) DCS UNIT APIs --- ------------------ --- The DCS Unit APIs are used extensively within MOOSE. The UNIT class has for each DCS Unit API a corresponding method. --- To be able to distinguish easily in your code the difference between a UNIT API call and a DCS Unit API call, --- the first letter of the method is also capitalized. So, by example, the DCS Unit method @{Dcs.DCSWrapper.Unit#Unit.getName}() --- is implemented in the UNIT class as @{#UNIT.GetName}(). --- --- 1.3) Smoke, Flare Units --- ----------------------- --- The UNIT class provides methods to smoke or flare units easily. --- The @{#UNIT.SmokeBlue}(), @{#UNIT.SmokeGreen}(),@{#UNIT.SmokeOrange}(), @{#UNIT.SmokeRed}(), @{#UNIT.SmokeRed}() methods --- will smoke the unit in the corresponding color. Note that smoking a unit is done at the current position of the DCS Unit. --- When the DCS Unit moves for whatever reason, the smoking will still continue! --- The @{#UNIT.FlareGreen}(), @{#UNIT.FlareRed}(), @{#UNIT.FlareWhite}(), @{#UNIT.FlareYellow}() --- methods will fire off a flare in the air with the corresponding color. Note that a flare is a one-off shot and its effect is of very short duration. --- --- 1.4) Location Position, Point --- ----------------------------- --- The UNIT class provides methods to obtain the current point or position of the DCS Unit. --- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively. --- If you want to obtain the complete **3D position** including ori�ntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively. --- --- 1.5) Test if alive --- ------------------ --- The @{#UNIT.IsAlive}(), @{#UNIT.IsActive}() methods determines if the DCS Unit is alive, meaning, it is existing and active. --- --- 1.6) Test for proximity --- ----------------------- --- The UNIT class contains methods to test the location or proximity against zones or other objects. --- --- ### 1.6.1) Zones --- To test whether the Unit is within a **zone**, use the @{#UNIT.IsInZone}() or the @{#UNIT.IsNotInZone}() methods. Any zone can be tested on, but the zone must be derived from @{Core.Zone#ZONE_BASE}. --- --- ### 1.6.2) Units --- Test if another DCS Unit is within a given radius of the current DCS Unit, use the @{#UNIT.OtherUnitInRadius}() method. --- --- @module Unit --- @author FlightControl - - - - - ---- The UNIT class --- @type UNIT --- @extends Wrapper.Controllable#CONTROLLABLE -UNIT = { - ClassName="UNIT", -} - - ---- Unit.SensorType --- @type Unit.SensorType --- @field OPTIC --- @field RADAR --- @field IRST --- @field RWR - - --- Registration. - ---- Create a new UNIT from DCSUnit. --- @param #UNIT self --- @param #string UnitName The name of the DCS unit. --- @return #UNIT -function UNIT:Register( UnitName ) - local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) - self.UnitName = UnitName - return self -end - --- Reference methods. - ---- Finds a UNIT from the _DATABASE using a DCSUnit object. --- @param #UNIT self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit An existing DCS Unit object reference. --- @return #UNIT self -function UNIT:Find( DCSUnit ) - - local UnitName = DCSUnit:getName() - local UnitFound = _DATABASE:FindUnit( UnitName ) - return UnitFound -end - ---- Find a UNIT in the _DATABASE using the name of an existing DCS Unit. --- @param #UNIT self --- @param #string UnitName The Unit Name. --- @return #UNIT self -function UNIT:FindByName( UnitName ) - - local UnitFound = _DATABASE:FindUnit( UnitName ) - return UnitFound -end - ---- Return the name of the UNIT. --- @param #UNIT self --- @return #string The UNIT name. -function UNIT:Name() - - return self.UnitName -end - - ---- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit -function UNIT:GetDCSObject() - - local DCSUnit = Unit.getByName( self.UnitName ) - - if DCSUnit then - return DCSUnit - end - - return nil -end - ---- Respawn the @{Unit} using a (tweaked) template of the parent Group. --- --- This function will: --- --- * Get the current position and heading of the group. --- * When the unit is alive, it will tweak the template x, y and heading coordinates of the group and the embedded units to the current units positions. --- * Then it will respawn the re-modelled group. --- --- @param #UNIT self --- @param Dcs.DCSTypes#Vec3 SpawnVec3 The position where to Spawn the new Unit at. --- @param #number Heading The heading of the unit respawn. -function UNIT:ReSpawn( SpawnVec3, Heading ) - - local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) - self:T( SpawnGroupTemplate ) - - local SpawnGroup = self:GetGroup() - - if SpawnGroup then - - local Vec3 = SpawnGroup:GetVec3() - SpawnGroupTemplate.x = SpawnVec3.x - SpawnGroupTemplate.y = SpawnVec3.z - - self:E( #SpawnGroupTemplate.units ) - for UnitID, UnitData in pairs( SpawnGroup:GetUnits() ) do - local GroupUnit = UnitData -- #UNIT - self:E( GroupUnit:GetName() ) - if GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - SpawnGroupTemplate.units[UnitID].alt = GroupUnitVec3.y - SpawnGroupTemplate.units[UnitID].x = GroupUnitVec3.x - SpawnGroupTemplate.units[UnitID].y = GroupUnitVec3.z - SpawnGroupTemplate.units[UnitID].heading = GroupUnitHeading - self:E( { UnitID, SpawnGroupTemplate.units[UnitID], SpawnGroupTemplate.units[UnitID] } ) - end - end - end - - for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do - self:T( UnitTemplateData.name ) - if UnitTemplateData.name == self:Name() then - self:T("Adjusting") - SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y - SpawnGroupTemplate.units[UnitTemplateID].x = SpawnVec3.x - SpawnGroupTemplate.units[UnitTemplateID].y = SpawnVec3.z - SpawnGroupTemplate.units[UnitTemplateID].heading = Heading - self:E( { UnitTemplateID, SpawnGroupTemplate.units[UnitTemplateID], SpawnGroupTemplate.units[UnitTemplateID] } ) - else - self:E( SpawnGroupTemplate.units[UnitTemplateID].name ) - local GroupUnit = UNIT:FindByName( SpawnGroupTemplate.units[UnitTemplateID].name ) -- #UNIT - if GroupUnit and GroupUnit:IsAlive() then - local GroupUnitVec3 = GroupUnit:GetVec3() - local GroupUnitHeading = GroupUnit:GetHeading() - UnitTemplateData.alt = GroupUnitVec3.y - UnitTemplateData.x = GroupUnitVec3.x - UnitTemplateData.y = GroupUnitVec3.z - UnitTemplateData.heading = GroupUnitHeading - else - if SpawnGroupTemplate.units[UnitTemplateID].name ~= self:Name() then - self:T("nilling") - SpawnGroupTemplate.units[UnitTemplateID].delete = true - end - end - end - end - - -- Remove obscolete units from the group structure - i = 1 - while i <= #SpawnGroupTemplate.units do - - local UnitTemplateData = SpawnGroupTemplate.units[i] - self:T( UnitTemplateData.name ) - - if UnitTemplateData.delete then - table.remove( SpawnGroupTemplate.units, i ) - else - i = i + 1 - end - end - - _DATABASE:Spawn( SpawnGroupTemplate ) -end - - - ---- Returns if the unit is activated. --- @param #UNIT self --- @return #boolean true if Unit is activated. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsActive() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - - local UnitIsActive = DCSUnit:isActive() - return UnitIsActive - end - - return nil -end - - - ---- Returns the Unit's callsign - the localized string. --- @param #UNIT self --- @return #string The Callsign of the Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCallsign() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitCallSign = DCSUnit:getCallsign() - return UnitCallSign - end - - self:E( self.ClassName .. " " .. self.UnitName .. " not found!" ) - return nil -end - - ---- Returns name of the player that control the unit or nil if the unit is controlled by A.I. --- @param #UNIT self --- @return #string Player Name --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPlayerName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - - local PlayerName = DCSUnit:getPlayerName() - if PlayerName == nil then - PlayerName = "" - end - return PlayerName - end - - return nil -end - ---- Returns the unit's number in the group. --- The number is the same number the unit has in ME. --- It may not be changed during the mission. --- If any unit in the group is destroyed, the numbers of another units will not be changed. --- @param #UNIT self --- @return #number The Unit number. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetNumber() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitNumber = DCSUnit:getNumber() - return UnitNumber - end - - return nil -end - ---- Returns the unit's group if it exist and nil otherwise. --- @param Wrapper.Unit#UNIT self --- @return Wrapper.Group#GROUP The Group of the Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetGroup() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) - return UnitGroup - end - - return nil -end - - --- Need to add here functions to check if radar is on and which object etc. - ---- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign. --- DCS Units spawned with the @{SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name. --- The spawn sequence number and unit number are contained within the name after the '#' sign. --- @param #UNIT self --- @return #string The name of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPrefix() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix - end - - return nil -end - ---- Returns the Unit's ammunition. --- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Ammo --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetAmmo() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitAmmo = DCSUnit:getAmmo() - return UnitAmmo - end - - return nil -end - ---- Returns the unit sensors. --- @param #UNIT self --- @return Dcs.DCSWrapper.Unit#Unit.Sensors --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetSensors() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitSensors = DCSUnit:getSensors() - return UnitSensors - end - - return nil -end - --- Need to add here a function per sensortype --- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS) - ---- Returns if the unit has sensors of a certain type. --- @param #UNIT self --- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:HasSensors( ... ) - self:F2( arg ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local HasSensors = DCSUnit:hasSensors( unpack( arg ) ) - return HasSensors - end - - return nil -end - ---- Returns if the unit is SEADable. --- @param #UNIT self --- @return #boolean returns true if the unit is SEADable. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:HasSEAD() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitSEADAttributes = DCSUnit:getDesc().attributes - - local HasSEAD = false - if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or - UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true then - HasSEAD = true - end - return HasSEAD - end - - return nil -end - ---- Returns two values: --- --- * First value indicates if at least one of the unit's radar(s) is on. --- * Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @param #UNIT self --- @return #boolean Indicates if at least one of the unit's radar(s) is on. --- @return Dcs.DCSWrapper.Object#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetRadar() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() - return UnitRadarOn, UnitRadarObject - end - - return nil, nil -end - ---- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0. --- @param #UNIT self --- @return #number The relative amount of fuel (from 0.0 to 1.0). --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetFuel() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitFuel = DCSUnit:getFuel() - return UnitFuel - end - - return nil -end - ---- Returns the unit's health. Dead units has health <= 1.0. --- @param #UNIT self --- @return #number The Unit's health value. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetLife() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitLife = DCSUnit:getLife() - return UnitLife - end - - return nil -end - ---- Returns the Unit's initial health. --- @param #UNIT self --- @return #number The Unit's initial health value. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetLife0() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitLife0 = DCSUnit:getLife0() - return UnitLife0 - end - - return nil -end - ---- Returns the Unit's A2G threat level on a scale from 1 to 10 ... --- The following threat levels are foreseen: --- --- * Threat level 0: Unit is unarmed. --- * Threat level 1: Unit is infantry. --- * Threat level 2: Unit is an infantry vehicle. --- * Threat level 3: Unit is ground artillery. --- * Threat level 4: Unit is a tank. --- * Threat level 5: Unit is a modern tank or ifv with ATGM. --- * Threat level 6: Unit is a AAA. --- * Threat level 7: Unit is a SAM or manpad, IR guided. --- * Threat level 8: Unit is a Short Range SAM, radar guided. --- * Threat level 9: Unit is a Medium Range SAM, radar guided. --- * Threat level 10: Unit is a Long Range SAM, radar guided. -function UNIT:GetThreatLevel() - - local Attributes = self:GetDesc().attributes - local ThreatLevel = 0 - - local ThreatLevels = { - "Unarmed", - "Infantry", - "Old Tanks & APCs", - "Tanks & IFVs without ATGM", - "Tanks & IFV with ATGM", - "Modern Tanks", - "AAA", - "IR Guided SAMs", - "SR SAMs", - "MR SAMs", - "LR SAMs" - } - - self:T2( Attributes ) - - if Attributes["LR SAM"] then ThreatLevel = 10 - elseif Attributes["MR SAM"] then ThreatLevel = 9 - elseif Attributes["SR SAM"] and - not Attributes["IR Guided SAM"] then ThreatLevel = 8 - elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and - Attributes["IR Guided SAM"] then ThreatLevel = 7 - elseif Attributes["AAA"] then ThreatLevel = 6 - elseif Attributes["Modern Tanks"] then ThreatLevel = 5 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - Attributes["ATGM"] then ThreatLevel = 4 - elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and - not Attributes["ATGM"] then ThreatLevel = 3 - elseif Attributes["Old Tanks"] or Attributes["APC"] then ThreatLevel = 2 - elseif Attributes["Infantry"] then ThreatLevel = 1 - end - - self:T2( ThreatLevel ) - return ThreatLevel, ThreatLevels[ThreatLevel+1] - -end - - --- Is functions - ---- Returns true if the unit is within a @{Zone}. --- @param #UNIT self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE} -function UNIT:IsInZone( Zone ) - self:F2( { self.UnitName, Zone } ) - - if self:IsAlive() then - local IsInZone = Zone:IsPointVec3InZone( self:GetVec3() ) - - self:T( { IsInZone } ) - return IsInZone - end - - return false -end - ---- Returns true if the unit is not within a @{Zone}. --- @param #UNIT self --- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE} -function UNIT:IsNotInZone( Zone ) - self:F2( { self.UnitName, Zone } ) - - if self:IsAlive() then - local IsInZone = not Zone:IsPointVec3InZone( self:GetVec3() ) - - self:T( { IsInZone } ) - return IsInZone - else - return false - end -end - - ---- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. --- @param #UNIT self --- @param #UNIT AwaitUnit The other UNIT wrapper object. --- @param Radius The radius in meters with the DCS Unit in the centre. --- @return true If the other DCS Unit is within the radius of the 2D point of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) - self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitVec3 = self:GetVec3() - local AwaitUnitVec3 = AwaitUnit:GetVec3() - - if (((UnitVec3.x - AwaitUnitVec3.x)^2 + (UnitVec3.z - AwaitUnitVec3.z)^2)^0.5 <= Radius) then - self:T3( "true" ) - return true - else - self:T3( "false" ) - return false - end - end - - return nil -end - - - ---- Signal a flare at the position of the UNIT. --- @param #UNIT self --- @param Utilities.Utils#FLARECOLOR FlareColor -function UNIT:Flare( FlareColor ) - self:F2() - trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 ) -end - ---- Signal a white flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareWhite() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 ) -end - ---- Signal a yellow flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareYellow() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 ) -end - ---- Signal a green flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareGreen() - self:F2() - trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 ) -end - ---- Signal a red flare at the position of the UNIT. --- @param #UNIT self -function UNIT:FlareRed() - self:F2() - local Vec3 = self:GetVec3() - if Vec3 then - trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 ) - end -end - ---- Smoke the UNIT. --- @param #UNIT self -function UNIT:Smoke( SmokeColor, Range ) - self:F2() - if Range then - trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor ) - else - trigger.action.smoke( self:GetVec3(), SmokeColor ) - end - -end - ---- Smoke the UNIT Green. --- @param #UNIT self -function UNIT:SmokeGreen() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green ) -end - ---- Smoke the UNIT Red. --- @param #UNIT self -function UNIT:SmokeRed() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red ) -end - ---- Smoke the UNIT White. --- @param #UNIT self -function UNIT:SmokeWhite() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White ) -end - ---- Smoke the UNIT Orange. --- @param #UNIT self -function UNIT:SmokeOrange() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange ) -end - ---- Smoke the UNIT Blue. --- @param #UNIT self -function UNIT:SmokeBlue() - self:F2() - trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue ) -end - --- Is methods - ---- Returns if the unit is of an air category. --- If the unit is a helicopter or a plane, then this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Air category evaluation result. -function UNIT:IsAir() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) - - local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) - - self:T3( IsAirResult ) - return IsAirResult - end - - return nil -end - ---- Returns if the unit is of an ground category. --- If the unit is a ground vehicle or infantry, this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Ground category evaluation result. -function UNIT:IsGround() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) - - local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) - - self:T3( IsGroundResult ) - return IsGroundResult - end - - return nil -end - ---- Returns if the unit is a friendly unit. --- @param #UNIT self --- @return #boolean IsFriendly evaluation result. -function UNIT:IsFriendly( FriendlyCoalition ) - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitCoalition = DCSUnit:getCoalition() - self:T3( { UnitCoalition, FriendlyCoalition } ) - - local IsFriendlyResult = ( UnitCoalition == FriendlyCoalition ) - - self:E( IsFriendlyResult ) - return IsFriendlyResult - end - - return nil -end - ---- Returns if the unit is of a ship category. --- If the unit is a ship, this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Ship category evaluation result. -function UNIT:IsShip() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.SHIP } ) - - local IsShipResult = ( UnitDescriptor.category == Unit.Category.SHIP ) - - self:T3( IsShipResult ) - return IsShipResult - end - - return nil -end - ---- This module contains the CLIENT class. --- --- 1) @{Wrapper.Client#CLIENT} class, extends @{Wrapper.Unit#UNIT} --- =============================================== --- Clients are those **Units** defined within the Mission Editor that have the skillset defined as __Client__ or __Player__. --- Note that clients are NOT the same as Units, they are NOT necessarily alive. --- The @{Wrapper.Client#CLIENT} class is a wrapper class to handle the DCS Unit objects that have the skillset defined as __Client__ or __Player__: --- --- * Wraps the DCS Unit objects with skill level set to Player or Client. --- * Support all DCS Unit APIs. --- * Enhance with Unit specific APIs not in the DCS Group API set. --- * When player joins Unit, execute alive init logic. --- * Handles messages to players. --- * Manage the "state" of the DCS Unit. --- --- Clients are being used by the @{MISSION} class to follow players and register their successes. --- --- 1.1) CLIENT reference methods --- ----------------------------- --- For each DCS Unit having skill level Player or Client, a CLIENT wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The CLIENT class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the DCS Unit or the DCS UnitName. --- --- Another thing to know is that CLIENT objects do not "contain" the DCS Unit object. --- The CLIENT methods will reference the DCS Unit object by name when it is needed during API execution. --- If the DCS Unit object does not exist or is nil, the CLIENT methods will return nil and log an exception in the DCS.log file. --- --- The CLIENT class provides the following functions to retrieve quickly the relevant CLIENT instance: --- --- * @{#CLIENT.Find}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit object. --- * @{#CLIENT.FindByName}(): Find a CLIENT instance from the _DATABASE object using a DCS Unit name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these CLIENT OBJECT REFERENCES! (make the CLIENT object references nil). --- --- @module Client --- @author FlightControl - ---- The CLIENT class --- @type CLIENT --- @extends Wrapper.Unit#UNIT -CLIENT = { - ONBOARDSIDE = { - NONE = 0, - LEFT = 1, - RIGHT = 2, - BACK = 3, - FRONT = 4 - }, - ClassName = "CLIENT", - ClientName = nil, - ClientAlive = false, - ClientTransport = false, - ClientBriefingShown = false, - _Menus = {}, - _Tasks = {}, - Messages = { - } -} - - ---- Finds a CLIENT from the _DATABASE using the relevant DCS Unit. --- @param #CLIENT self --- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. --- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @return #CLIENT --- @usage --- -- Create new Clients. --- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) --- Mission:AddGoal( DeploySA6TroopsGoal ) --- --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) -function CLIENT:Find( DCSUnit ) - local ClientName = DCSUnit:getName() - local ClientFound = _DATABASE:FindClient( ClientName ) - - if ClientFound then - ClientFound:F( ClientName ) - return ClientFound - end - - error( "CLIENT not found for: " .. ClientName ) -end - - ---- Finds a CLIENT from the _DATABASE using the relevant Client Unit Name. --- As an optional parameter, a briefing text can be given also. --- @param #CLIENT self --- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor. --- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client. --- @param #boolean Error A flag that indicates whether an error should be raised if the CLIENT cannot be found. By default an error will be raised. --- @return #CLIENT --- @usage --- -- Create new Clients. --- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' ) --- Mission:AddGoal( DeploySA6TroopsGoal ) --- --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) -function CLIENT:FindByName( ClientName, ClientBriefing, Error ) - local ClientFound = _DATABASE:FindClient( ClientName ) - - if ClientFound then - ClientFound:F( { ClientName, ClientBriefing } ) - ClientFound:AddBriefing( ClientBriefing ) - ClientFound.MessageSwitch = true - - return ClientFound - end - - if not Error then - error( "CLIENT not found for: " .. ClientName ) - end -end - -function CLIENT:Register( ClientName ) - local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) - - self:F( ClientName ) - self.ClientName = ClientName - self.MessageSwitch = true - self.ClientAlive2 = false - - --self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 ) - self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5 ) - - self:E( self ) - return self -end - - ---- Transport defines that the Client is a Transport. Transports show cargo. --- @param #CLIENT self --- @return #CLIENT -function CLIENT:Transport() - self:F() - - self.ClientTransport = true - return self -end - ---- AddBriefing adds a briefing to a CLIENT when a player joins a mission. --- @param #CLIENT self --- @param #string ClientBriefing is the text defining the Mission briefing. --- @return #CLIENT self -function CLIENT:AddBriefing( ClientBriefing ) - self:F( ClientBriefing ) - self.ClientBriefing = ClientBriefing - self.ClientBriefingShown = false - - return self -end - ---- Show the briefing of a CLIENT. --- @param #CLIENT self --- @return #CLIENT self -function CLIENT:ShowBriefing() - self:F( { self.ClientName, self.ClientBriefingShown } ) - - if not self.ClientBriefingShown then - self.ClientBriefingShown = true - local Briefing = "" - if self.ClientBriefing then - Briefing = Briefing .. self.ClientBriefing - end - Briefing = Briefing .. " Press [LEFT ALT]+[B] to view the complete mission briefing." - self:Message( Briefing, 60, "Briefing" ) - end - - return self -end - ---- Show the mission briefing of a MISSION to the CLIENT. --- @param #CLIENT self --- @param #string MissionBriefing --- @return #CLIENT self -function CLIENT:ShowMissionBriefing( MissionBriefing ) - self:F( { self.ClientName } ) - - if MissionBriefing then - self:Message( MissionBriefing, 60, "Mission Briefing" ) - end - - return self -end - - - ---- Resets a CLIENT. --- @param #CLIENT self --- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. -function CLIENT:Reset( ClientName ) - self:F() - self._Menus = {} -end - --- Is Functions - ---- Checks if the CLIENT is a multi-seated UNIT. --- @param #CLIENT self --- @return #boolean true if multi-seated. -function CLIENT:IsMultiSeated() - self:F( self.ClientName ) - - local ClientMultiSeatedTypes = { - ["Mi-8MT"] = "Mi-8MT", - ["UH-1H"] = "UH-1H", - ["P-51B"] = "P-51B" - } - - if self:IsAlive() then - local ClientTypeName = self:GetClientGroupUnit():GetTypeName() - if ClientMultiSeatedTypes[ClientTypeName] then - return true - end - end - - return false -end - ---- Checks for a client alive event and calls a function on a continuous basis. --- @param #CLIENT self --- @param #function CallBack Function. --- @return #CLIENT -function CLIENT:Alive( CallBackFunction, ... ) - self:F() - - self.ClientCallBack = CallBackFunction - self.ClientParameters = arg - - return self -end - ---- @param #CLIENT self -function CLIENT:_AliveCheckScheduler( SchedulerName ) - self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } ) - - if self:IsAlive() then - if self.ClientAlive2 == false then - self:ShowBriefing() - if self.ClientCallBack then - self:T("Calling Callback function") - self.ClientCallBack( self, unpack( self.ClientParameters ) ) - end - self.ClientAlive2 = true - end - else - if self.ClientAlive2 == true then - self.ClientAlive2 = false - end - end - - return true -end - ---- Return the DCSGroup of a Client. --- This function is modified to deal with a couple of bugs in DCS 1.5.3 --- @param #CLIENT self --- @return Dcs.DCSWrapper.Group#Group -function CLIENT:GetDCSGroup() - self:F3() - --- local ClientData = Group.getByName( self.ClientName ) --- if ClientData and ClientData:isExist() then --- self:T( self.ClientName .. " : group found!" ) --- return ClientData --- else --- return nil --- end - - local ClientUnit = Unit.getByName( self.ClientName ) - - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - self:T3( { "CoalitionData:", CoalitionData } ) - for UnitId, UnitData in pairs( CoalitionData ) do - self:T3( { "UnitData:", UnitData } ) - if UnitData and UnitData:isExist() then - - --self:E(self.ClientName) - if ClientUnit then - local ClientGroup = ClientUnit:getGroup() - if ClientGroup then - self:T3( "ClientGroup = " .. self.ClientName ) - if ClientGroup:isExist() and UnitData:getGroup():isExist() then - if ClientGroup:getID() == UnitData:getGroup():getID() then - self:T3( "Normal logic" ) - self:T3( self.ClientName .. " : group found!" ) - self.ClientGroupID = ClientGroup:getID() - self.ClientGroupName = ClientGroup:getName() - return ClientGroup - end - else - -- Now we need to resolve the bugs in DCS 1.5 ... - -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) - self:T3( "Bug 1.5 logic" ) - local ClientGroupTemplate = _DATABASE.Templates.Units[self.ClientName].GroupTemplate - self.ClientGroupID = ClientGroupTemplate.groupId - self.ClientGroupName = _DATABASE.Templates.Units[self.ClientName].GroupName - self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) - return ClientGroup - end - -- else - -- error( "Client " .. self.ClientName .. " not found!" ) - end - else - --self:E( { "Client not found!", self.ClientName } ) - end - end - end - end - - -- For non player clients - if ClientUnit then - local ClientGroup = ClientUnit:getGroup() - if ClientGroup then - self:T3( "ClientGroup = " .. self.ClientName ) - if ClientGroup:isExist() then - self:T3( "Normal logic" ) - self:T3( self.ClientName .. " : group found!" ) - return ClientGroup - end - end - end - - self.ClientGroupID = nil - self.ClientGroupUnit = nil - - return nil -end - - --- TODO: Check Dcs.DCSTypes#Group.ID ---- Get the group ID of the client. --- @param #CLIENT self --- @return Dcs.DCSTypes#Group.ID -function CLIENT:GetClientGroupID() - - local ClientGroup = self:GetDCSGroup() - - --self:E( self.ClientGroupID ) -- Determined in GetDCSGroup() - return self.ClientGroupID -end - - ---- Get the name of the group of the client. --- @param #CLIENT self --- @return #string -function CLIENT:GetClientGroupName() - - local ClientGroup = self:GetDCSGroup() - - self:T( self.ClientGroupName ) -- Determined in GetDCSGroup() - return self.ClientGroupName -end - ---- Returns the UNIT of the CLIENT. --- @param #CLIENT self --- @return Wrapper.Unit#UNIT -function CLIENT:GetClientGroupUnit() - self:F2() - - local ClientDCSUnit = Unit.getByName( self.ClientName ) - - self:T( self.ClientDCSUnit ) - if ClientDCSUnit and ClientDCSUnit:isExist() then - local ClientUnit = _DATABASE:FindUnit( self.ClientName ) - self:T2( ClientUnit ) - return ClientUnit - end -end - ---- Returns the DCSUnit of the CLIENT. --- @param #CLIENT self --- @return Dcs.DCSTypes#Unit -function CLIENT:GetClientGroupDCSUnit() - self:F2() - - local ClientDCSUnit = Unit.getByName( self.ClientName ) - - if ClientDCSUnit and ClientDCSUnit:isExist() then - self:T2( ClientDCSUnit ) - return ClientDCSUnit - end -end - - ---- Evaluates if the CLIENT is a transport. --- @param #CLIENT self --- @return #boolean true is a transport. -function CLIENT:IsTransport() - self:F() - return self.ClientTransport -end - ---- Shows the @{AI.AI_Cargo#CARGO} contained within the CLIENT to the player as a message. --- The @{AI.AI_Cargo#CARGO} is shown using the @{Core.Message#MESSAGE} distribution system. --- @param #CLIENT self -function CLIENT:ShowCargo() - self:F() - - local CargoMsg = "" - - for CargoName, Cargo in pairs( CARGOS ) do - if self == Cargo:IsLoadedInClient() then - CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n" - end - end - - if CargoMsg == "" then - CargoMsg = "empty" - end - - self:Message( CargoMsg, 15, "Co-Pilot: Cargo Status", 30 ) - -end - --- TODO (1) I urgently need to revise this. ---- A local function called by the DCS World Menu system to switch off messages. -function CLIENT.SwitchMessages( PrmTable ) - PrmTable[1].MessageSwitch = PrmTable[2] -end - ---- The main message driver for the CLIENT. --- This function displays various messages to the Player logged into the CLIENT through the DCS World Messaging system. --- @param #CLIENT self --- @param #string Message is the text describing the message. --- @param #number MessageDuration is the duration in seconds that the Message should be displayed. --- @param #string MessageCategory is the category of the message (the title). --- @param #number MessageInterval is the interval in seconds between the display of the @{Core.Message#MESSAGE} when the CLIENT is in the air. --- @param #string MessageID is the identifier of the message when displayed with intervals. -function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInterval, MessageID ) - self:F( { Message, MessageDuration, MessageCategory, MessageInterval } ) - - if self.MessageSwitch == true then - if MessageCategory == nil then - MessageCategory = "Messages" - end - if MessageID ~= nil then - if self.Messages[MessageID] == nil then - self.Messages[MessageID] = {} - self.Messages[MessageID].MessageId = MessageID - self.Messages[MessageID].MessageTime = timer.getTime() - self.Messages[MessageID].MessageDuration = MessageDuration - if MessageInterval == nil then - self.Messages[MessageID].MessageInterval = 600 - else - self.Messages[MessageID].MessageInterval = MessageInterval - end - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - else - if self:GetClientGroupDCSUnit() and not self:GetClientGroupDCSUnit():inAir() then - if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + 10 then - MESSAGE:New( Message, MessageDuration , MessageCategory):ToClient( self ) - self.Messages[MessageID].MessageTime = timer.getTime() - end - else - if timer.getTime() - self.Messages[MessageID].MessageTime >= self.Messages[MessageID].MessageDuration + self.Messages[MessageID].MessageInterval then - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - self.Messages[MessageID].MessageTime = timer.getTime() - end - end - end - else - MESSAGE:New( Message, MessageDuration, MessageCategory ):ToClient( self ) - end - end -end ---- This module contains the STATIC class. --- --- 1) @{Wrapper.Static#STATIC} class, extends @{Wrapper.Positionable#POSITIONABLE} --- =============================================================== --- Statics are **Static Units** defined within the Mission Editor. --- Note that Statics are almost the same as Units, but they don't have a controller. --- The @{Wrapper.Static#STATIC} class is a wrapper class to handle the DCS Static objects: --- --- * Wraps the DCS Static objects. --- * Support all DCS Static APIs. --- * Enhance with Static specific APIs not in the DCS API set. --- --- 1.1) STATIC reference methods --- ----------------------------- --- For each DCS Static will have a STATIC wrapper object (instance) within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The STATIC class does not contain a :New() method, rather it provides :Find() methods to retrieve the object reference --- using the Static Name. --- --- Another thing to know is that STATIC objects do not "contain" the DCS Static object. --- The STATIc methods will reference the DCS Static object by name when it is needed during API execution. --- If the DCS Static object does not exist or is nil, the STATIC methods will return nil and log an exception in the DCS.log file. --- --- The STATIc class provides the following functions to retrieve quickly the relevant STATIC instance: --- --- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil). --- --- @module Static --- @author FlightControl - - - - - - ---- The STATIC class --- @type STATIC --- @extends Wrapper.Positionable#POSITIONABLE -STATIC = { - ClassName = "STATIC", -} - - ---- Finds a STATIC from the _DATABASE using the relevant Static Name. --- As an optional parameter, a briefing text can be given also. --- @param #STATIC self --- @param #string StaticName Name of the DCS **Static** as defined within the Mission Editor. --- @return #STATIC -function STATIC:FindByName( StaticName ) - local StaticFound = _DATABASE:FindStatic( StaticName ) - - self.StaticName = StaticName - - if StaticFound then - StaticFound:F( { StaticName } ) - - return StaticFound - end - - error( "STATIC not found for: " .. StaticName ) -end - -function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) - self.StaticName = StaticName - return self -end - - -function STATIC:GetDCSObject() - local DCSStatic = StaticObject.getByName( self.StaticName ) - - if DCSStatic then - return DCSStatic - end - - return nil -end ---- This module contains the AIRBASE classes. --- --- === --- --- 1) @{Wrapper.Airbase#AIRBASE} class, extends @{Wrapper.Positionable#POSITIONABLE} --- ================================================================= --- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: --- --- * Support all DCS Airbase APIs. --- * Enhance with Airbase specific APIs not in the DCS Airbase API set. --- --- --- 1.1) AIRBASE reference methods --- ------------------------------ --- For each DCS Airbase object alive within a running mission, a AIRBASE wrapper object (instance) will be created within the _@{DATABASE} object. --- This is done at the beginning of the mission (when the mission starts). --- --- The AIRBASE class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference --- using the DCS Airbase or the DCS AirbaseName. --- --- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object. --- The AIRBASE methods will reference the DCS Airbase object by name when it is needed during API execution. --- If the DCS Airbase object does not exist or is nil, the AIRBASE methods will return nil and log an exception in the DCS.log file. --- --- The AIRBASE class provides the following functions to retrieve quickly the relevant AIRBASE instance: --- --- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object. --- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name. --- --- IMPORTANT: ONE SHOULD NEVER SANATIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil). --- --- 1.2) DCS AIRBASE APIs --- --------------------- --- The DCS Airbase APIs are used extensively within MOOSE. The AIRBASE class has for each DCS Airbase API a corresponding method. --- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call, --- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{Dcs.DCSWrapper.Airbase#Airbase.getName}() --- is implemented in the AIRBASE class as @{#AIRBASE.GetName}(). --- --- More functions will be added --- ---------------------------- --- During the MOOSE development, more functions will be added. --- --- @module Airbase --- @author FlightControl - - - - - ---- The AIRBASE class --- @type AIRBASE --- @extends Wrapper.Positionable#POSITIONABLE -AIRBASE = { - ClassName="AIRBASE", - CategoryName = { - [Airbase.Category.AIRDROME] = "Airdrome", - [Airbase.Category.HELIPAD] = "Helipad", - [Airbase.Category.SHIP] = "Ship", - }, - } - --- Registration. - ---- Create a new AIRBASE from DCSAirbase. --- @param #AIRBASE self --- @param #string AirbaseName The name of the airbase. --- @return Wrapper.Airbase#AIRBASE -function AIRBASE:Register( AirbaseName ) - - local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) - self.AirbaseName = AirbaseName - return self -end - --- Reference methods. - ---- Finds a AIRBASE from the _DATABASE using a DCSAirbase object. --- @param #AIRBASE self --- @param Dcs.DCSWrapper.Airbase#Airbase DCSAirbase An existing DCS Airbase object reference. --- @return Wrapper.Airbase#AIRBASE self -function AIRBASE:Find( DCSAirbase ) - - local AirbaseName = DCSAirbase:getName() - local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) - return AirbaseFound -end - ---- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase. --- @param #AIRBASE self --- @param #string AirbaseName The Airbase Name. --- @return Wrapper.Airbase#AIRBASE self -function AIRBASE:FindByName( AirbaseName ) - - local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) - return AirbaseFound -end - -function AIRBASE:GetDCSObject() - local DCSAirbase = Airbase.getByName( self.AirbaseName ) - - if DCSAirbase then - return DCSAirbase - end - - return nil -end - - - ---- Scoring system for MOOSE. --- This scoring class calculates the hits and kills that players make within a simulation session. --- Scoring is calculated using a defined algorithm. --- With a small change in MissionScripting.lua, the scoring can also be logged in a CSV file, that can then be uploaded --- to a database or a BI tool to publish the scoring results to the player community. --- @module Scoring --- @author FlightControl - - ---- The Scoring class --- @type SCORING --- @field Players A collection of the current players that have joined the game. --- @extends Core.Base#BASE -SCORING = { - ClassName = "SCORING", - ClassID = 0, - Players = {}, -} - -local _SCORINGCoalition = - { - [1] = "Red", - [2] = "Blue", - } - -local _SCORINGCategory = - { - [Unit.Category.AIRPLANE] = "Plane", - [Unit.Category.HELICOPTER] = "Helicopter", - [Unit.Category.GROUND_UNIT] = "Vehicle", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - } - ---- Creates a new SCORING object to administer the scoring achieved by players. --- @param #SCORING self --- @param #string GameName The name of the game. This name is also logged in the CSV score file. --- @return #SCORING self --- @usage --- -- Define a new scoring object for the mission Gori Valley. --- ScoringObject = SCORING:New( "Gori Valley" ) -function SCORING:New( GameName ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - if GameName then - self.GameName = GameName - else - error( "A game name must be given to register the scoring results" ) - end - - - _EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self ) - _EVENTDISPATCHER:OnHit( self._EventOnHit, self ) - - --self.SchedulerId = routines.scheduleFunction( SCORING._FollowPlayersScheduled, { self }, 0, 5 ) - self.SchedulerId = SCHEDULER:New( self, self._FollowPlayersScheduled, {}, 0, 5 ) - - self:ScoreMenu() - - self:OpenCSV( GameName) - - return self - -end - ---- Creates a score radio menu. Can be accessed using Radio -> F10. --- @param #SCORING self --- @return #SCORING self -function SCORING:ScoreMenu() - self.Menu = MENU_MISSION:New( 'Scoring' ) - self.AllScoresMenu = MENU_MISSION_COMMAND:New( 'Score All Active Players', self.Menu, SCORING.ReportScoreAll, self ) - --- = COMMANDMENU:New('Your Current Score', ReportScore, SCORING.ReportScorePlayer, self ) - return self -end - ---- Follows new players entering Clients within the DCSRTE. --- TODO: Need to see if i can catch this also with an event. It will eliminate the schedule ... -function SCORING:_FollowPlayersScheduled() - self:F3( "_FollowPlayersScheduled" ) - - local ClientUnit = 0 - local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } - local unitId - local unitData - local AlivePlayerUnits = {} - - for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - self:T3( { "_FollowPlayersScheduled", CoalitionData } ) - for UnitId, UnitData in pairs( CoalitionData ) do - self:_AddPlayerFromUnit( UnitData ) - end - end - - return true -end - - ---- Track DEAD or CRASH events for the scoring. --- @param #SCORING self --- @param Core.Event#EVENTDATA Event -function SCORING:_EventOnDeadOrCrash( Event ) - self:F( { Event } ) - - local TargetUnit = nil - local TargetGroup = nil - local TargetUnitName = "" - local TargetGroupName = "" - local TargetPlayerName = "" - local TargetCoalition = nil - local TargetCategory = nil - local TargetType = nil - local TargetUnitCoalition = nil - local TargetUnitCategory = nil - local TargetUnitType = nil - - if Event.IniDCSUnit then - - TargetUnit = Event.IniDCSUnit - TargetUnitName = Event.IniDCSUnitName - TargetGroup = Event.IniDCSGroup - TargetGroupName = Event.IniDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() - - TargetCoalition = TargetUnit:getCoalition() - --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category -- Workaround - TargetType = TargetUnit:getTypeName() - - TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] - TargetUnitCategory = _SCORINGCategory[TargetCategory] - TargetUnitType = TargetType - - self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) - end - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Something got killed" ) - - -- Some variables - local InitUnitName = PlayerData.UnitName - local InitUnitType = PlayerData.UnitType - local InitCoalition = PlayerData.UnitCoalition - local InitCategory = PlayerData.UnitCategory - local InitUnitCoalition = _SCORINGCoalition[InitCoalition] - local InitUnitCategory = _SCORINGCategory[InitCategory] - - self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) - - -- What is he hitting? - if TargetCategory then - if PlayerData and PlayerData.Hit and PlayerData.Hit[TargetCategory] and PlayerData.Hit[TargetCategory][TargetUnitName] then -- Was there a hit for this unit for this player before registered??? - if not PlayerData.Kill[TargetCategory] then - PlayerData.Kill[TargetCategory] = {} - end - if not PlayerData.Kill[TargetCategory][TargetType] then - PlayerData.Kill[TargetCategory][TargetType] = {} - PlayerData.Kill[TargetCategory][TargetType].Score = 0 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = 0 - PlayerData.Kill[TargetCategory][TargetType].Penalty = 0 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0 - end - - if InitCoalition == TargetCoalition then - PlayerData.Penalty = PlayerData.Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].Penalty = PlayerData.Kill[TargetCategory][TargetType].Penalty + 25 - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Penalty: -" .. PlayerData.Kill[TargetCategory][TargetType].Penalty .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - PlayerData.Score = PlayerData.Score + 10 - PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10 - PlayerData.Kill[TargetCategory][TargetType].ScoreKill = PlayerData.Kill[TargetCategory][TargetType].ScoreKill + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' killed an enemy " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - PlayerData.Kill[TargetCategory][TargetType].ScoreKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Score .. - ". Score Total:" .. PlayerData.Score - PlayerData.Penalty, - 5 ):ToAll() - self:ScoreCSV( PlayerName, "KILL_SCORE", 1, 10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end - end - end - end -end - - - ---- Add a new player entering a Unit. -function SCORING:_AddPlayerFromUnit( UnitData ) - self:F( UnitData ) - - if UnitData and UnitData:isExist() then - local UnitName = UnitData:getName() - local PlayerName = UnitData:getPlayerName() - local UnitDesc = UnitData:getDesc() - local UnitCategory = UnitDesc.category - local UnitCoalition = UnitData:getCoalition() - local UnitTypeName = UnitData:getTypeName() - - self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } ) - - if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ... - self.Players[PlayerName] = {} - self.Players[PlayerName].Hit = {} - self.Players[PlayerName].Kill = {} - self.Players[PlayerName].Mission = {} - - -- for CategoryID, CategoryName in pairs( SCORINGCategory ) do - -- self.Players[PlayerName].Hit[CategoryID] = {} - -- self.Players[PlayerName].Kill[CategoryID] = {} - -- end - self.Players[PlayerName].HitPlayers = {} - self.Players[PlayerName].HitUnits = {} - self.Players[PlayerName].Score = 0 - self.Players[PlayerName].Penalty = 0 - self.Players[PlayerName].PenaltyCoalition = 0 - self.Players[PlayerName].PenaltyWarning = 0 - end - - if not self.Players[PlayerName].UnitCoalition then - self.Players[PlayerName].UnitCoalition = UnitCoalition - else - if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then - self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50 - self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1 - MESSAGE:New( "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. - "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.", - 2 - ):ToAll() - self:ScoreCSV( PlayerName, "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, - UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:getTypeName() ) - end - end - self.Players[PlayerName].UnitName = UnitName - self.Players[PlayerName].UnitCoalition = UnitCoalition - self.Players[PlayerName].UnitCategory = UnitCategory - self.Players[PlayerName].UnitType = UnitTypeName - - if self.Players[PlayerName].Penalty > 100 then - if self.Players[PlayerName].PenaltyWarning < 1 then - MESSAGE:New( "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than 150, you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty, - 30 - ):ToAll() - self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1 - end - end - - if self.Players[PlayerName].Penalty > 150 then - ClientGroup = GROUP:NewFromDCSUnit( UnitData ) - ClientGroup:Destroy() - MESSAGE:New( "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!", - 10 - ):ToAll() - end - - end -end - - ---- Registers Scores the players completing a Mission Task. --- @param #SCORING self --- @param Tasking.Mission#MISSION Mission --- @param Wrapper.Unit#UNIT PlayerUnit --- @param #string Text --- @param #number Score -function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) - - local PlayerName = PlayerUnit:GetPlayerName() - local MissionName = Mission:GetName() - - self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } ) - - local PlayerData = self.Players[PlayerName] - - if not PlayerData.Mission[MissionName] then - PlayerData.Mission[MissionName] = {} - PlayerData.Mission[MissionName].ScoreTask = 0 - PlayerData.Mission[MissionName].ScoreMission = 0 - end - - self:T( PlayerName ) - self:T( PlayerData.Mission[MissionName] ) - - PlayerData.Score = self.Players[PlayerName].Score + Score - PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score - - MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. - Score .. " task score!", - 30 ):ToAll() - - self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) -end - - ---- Registers Mission Scores for possible multiple players that contributed in the Mission. --- @param #SCORING self --- @param Tasking.Mission#MISSION Mission --- @param Wrapper.Unit#UNIT PlayerUnit --- @param #string Text --- @param #number Score -function SCORING:_AddMissionScore( Mission, Text, Score ) - - local MissionName = Mission:GetName() - - self:E( { Mission, Text, Score } ) - self:E( self.Players ) - - for PlayerName, PlayerData in pairs( self.Players ) do - - self:E( PlayerData ) - if PlayerData.Mission[MissionName] then - - PlayerData.Score = PlayerData.Score + Score - PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score - - MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. - Score .. " mission score!", - 60 ):ToAll() - - self:ScoreCSV( PlayerName, "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score ) - end - end -end - ---- Handles the OnHit event for the scoring. --- @param #SCORING self --- @param Core.Event#EVENTDATA Event -function SCORING:_EventOnHit( Event ) - self:F( { Event } ) - - local InitUnit = nil - local InitUnitName = "" - local InitGroup = nil - local InitGroupName = "" - local InitPlayerName = nil - - local InitCoalition = nil - local InitCategory = nil - local InitType = nil - local InitUnitCoalition = nil - local InitUnitCategory = nil - local InitUnitType = nil - - local TargetUnit = nil - local TargetUnitName = "" - local TargetGroup = nil - local TargetGroupName = "" - local TargetPlayerName = "" - - local TargetCoalition = nil - local TargetCategory = nil - local TargetType = nil - local TargetUnitCoalition = nil - local TargetUnitCategory = nil - local TargetUnitType = nil - - if Event.IniDCSUnit then - - InitUnit = Event.IniDCSUnit - InitUnitName = Event.IniDCSUnitName - InitGroup = Event.IniDCSGroup - InitGroupName = Event.IniDCSGroupName - InitPlayerName = InitUnit:getPlayerName() - - InitCoalition = InitUnit:getCoalition() - --TODO: Workaround Client DCS Bug - --InitCategory = InitUnit:getCategory() - InitCategory = InitUnit:getDesc().category - InitType = InitUnit:getTypeName() - - InitUnitCoalition = _SCORINGCoalition[InitCoalition] - InitUnitCategory = _SCORINGCategory[InitCategory] - InitUnitType = InitType - - self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } ) - end - - - if Event.TgtDCSUnit then - - TargetUnit = Event.TgtDCSUnit - TargetUnitName = Event.TgtDCSUnitName - TargetGroup = Event.TgtDCSGroup - TargetGroupName = Event.TgtDCSGroupName - TargetPlayerName = TargetUnit:getPlayerName() - - TargetCoalition = TargetUnit:getCoalition() - --TODO: Workaround Client DCS Bug - --TargetCategory = TargetUnit:getCategory() - TargetCategory = TargetUnit:getDesc().category - TargetType = TargetUnit:getTypeName() - - TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] - TargetUnitCategory = _SCORINGCategory[TargetCategory] - TargetUnitType = TargetType - - self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } ) - end - - if InitPlayerName ~= nil then -- It is a player that is hitting something - self:_AddPlayerFromUnit( InitUnit ) - if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway. - if TargetPlayerName ~= nil then -- It is a player hitting another player ... - self:_AddPlayerFromUnit( TargetUnit ) - self.Players[InitPlayerName].HitPlayers = self.Players[InitPlayerName].HitPlayers + 1 - end - - self:T( "Hitting Something" ) - -- What is he hitting? - if TargetCategory then - if not self.Players[InitPlayerName].Hit[TargetCategory] then - self.Players[InitPlayerName].Hit[TargetCategory] = {} - end - if not self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] then - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName] = {} - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = 0 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = 0 - end - local Score = 0 - if InitCoalition == TargetCoalition then - self.Players[InitPlayerName].Penalty = self.Players[InitPlayerName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty + 10 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit .. " times. Penalty: -" .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - else - self.Players[InitPlayerName].Score = self.Players[InitPlayerName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score + 1 - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit + 1 - MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. - self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].ScoreHit .. " times. Score: " .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Score .. - ". Score Total:" .. self.Players[InitPlayerName].Score - self.Players[InitPlayerName].Penalty, - 2 - ):ToAll() - self:ScoreCSV( InitPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - end - end - end - elseif InitPlayerName == nil then -- It is an AI hitting a player??? - - end -end - - -function SCORING:ReportScoreAll() - - env.info( "Hello World " ) - - local ScoreMessage = "" - local PlayerMessage = "" - - self:T( "Score Report" ) - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) - - -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName - - local PlayerScore = 0 - local PlayerPenalty = 0 - - ScoreMessage = ":\n" - - local ScoreMessageHits = "" - - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit - end - local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. "\n" - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( " %s:%d ", CategoryName, Score - Penalty ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. "\n" - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. " Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties .. "\n" - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")\n" - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score:%d (%d Score -%d Penalties)%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) - end - end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() -end - - -function SCORING:ReportScorePlayer() - - env.info( "Hello World " ) - - local ScoreMessage = "" - local PlayerMessage = "" - - self:T( "Score Report" ) - - for PlayerName, PlayerData in pairs( self.Players ) do - if PlayerData then -- This should normally not happen, but i'll test it anyway. - self:T( "Score Player: " .. PlayerName ) - - -- Some variables - local InitUnitCoalition = _SCORINGCoalition[PlayerData.UnitCoalition] - local InitUnitCategory = _SCORINGCategory[PlayerData.UnitCategory] - local InitUnitType = PlayerData.UnitType - local InitUnitName = PlayerData.UnitName - - local PlayerScore = 0 - local PlayerPenalty = 0 - - ScoreMessage = "" - - local ScoreMessageHits = "" - - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( CategoryName ) - if PlayerData.Hit[CategoryID] then - local Score = 0 - local ScoreHit = 0 - local Penalty = 0 - local PenaltyHit = 0 - self:T( "Hit scores exist for player " .. PlayerName ) - for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do - Score = Score + UnitData.Score - ScoreHit = ScoreHit + UnitData.ScoreHit - Penalty = Penalty + UnitData.Penalty - PenaltyHit = UnitData.PenaltyHit - end - local ScoreMessageHit = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreHit, PenaltyHit ) - self:T( ScoreMessageHit ) - ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageHits ~= "" then - ScoreMessage = ScoreMessage .. "\n Hits: " .. ScoreMessageHits .. " " - end - - local ScoreMessageKills = "" - for CategoryID, CategoryName in pairs( _SCORINGCategory ) do - self:T( "Kill scores exist for player " .. PlayerName ) - if PlayerData.Kill[CategoryID] then - local Score = 0 - local ScoreKill = 0 - local Penalty = 0 - local PenaltyKill = 0 - - for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do - Score = Score + UnitData.Score - ScoreKill = ScoreKill + UnitData.ScoreKill - Penalty = Penalty + UnitData.Penalty - PenaltyKill = PenaltyKill + UnitData.PenaltyKill - end - - local ScoreMessageKill = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreKill, PenaltyKill ) - self:T( ScoreMessageKill ) - ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill - - PlayerScore = PlayerScore + Score - PlayerPenalty = PlayerPenalty + Penalty - else - --ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 ) - end - end - if ScoreMessageKills ~= "" then - ScoreMessage = ScoreMessage .. "\n Kills: " .. ScoreMessageKills .. " " - end - - local ScoreMessageCoalitionChangePenalties = "" - if PlayerData.PenaltyCoalition ~= 0 then - ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition ) - PlayerPenalty = PlayerPenalty + PlayerData.Penalty - end - if ScoreMessageCoalitionChangePenalties ~= "" then - ScoreMessage = ScoreMessage .. "\n Coalition: " .. ScoreMessageCoalitionChangePenalties .. " " - end - - local ScoreMessageMission = "" - local ScoreMission = 0 - local ScoreTask = 0 - for MissionName, MissionData in pairs( PlayerData.Mission ) do - ScoreMission = ScoreMission + MissionData.ScoreMission - ScoreTask = ScoreTask + MissionData.ScoreTask - ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; " - end - PlayerScore = PlayerScore + ScoreMission + ScoreTask - - if ScoreMessageMission ~= "" then - ScoreMessage = ScoreMessage .. "\n Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") " - end - - PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties ):%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage ) - end - end - MESSAGE:New( PlayerMessage, 30, "Player Scores" ):ToAll() - -end - - -function SCORING:SecondsToClock(sSeconds) - local nSeconds = sSeconds - if nSeconds == 0 then - --return nil; - return "00:00:00"; - else - nHours = string.format("%02.f", math.floor(nSeconds/3600)); - nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); - nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); - return nHours..":"..nMins..":"..nSecs - end -end - ---- Opens a score CSV file to log the scores. --- @param #SCORING self --- @param #string ScoringCSV --- @return #SCORING self --- @usage --- -- Open a new CSV file to log the scores of the game Gori Valley. Let the name of the CSV file begin with "Player Scores". --- ScoringObject = SCORING:New( "Gori Valley" ) --- ScoringObject:OpenCSV( "Player Scores" ) -function SCORING:OpenCSV( ScoringCSV ) - self:F( ScoringCSV ) - - if lfs and io and os then - if ScoringCSV then - self.ScoringCSV = ScoringCSV - local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv" - - self.CSVFile, self.err = io.open( fdir, "w+" ) - if not self.CSVFile then - error( "Error: Cannot open CSV file in " .. lfs.writedir() ) - end - - self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' ) - - self.RunTime = os.date("%y-%m-%d_%H-%M-%S") - else - error( "A string containing the CSV file name must be given." ) - end - else - self:E( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." ) - end - return self -end - - ---- Registers a score for a player. --- @param #SCORING self --- @param #string PlayerName The name of the player. --- @param #string ScoreType The type of the score. --- @param #string ScoreTimes The amount of scores achieved. --- @param #string ScoreAmount The score given. --- @param #string PlayerUnitName The unit name of the player. --- @param #string PlayerUnitCoalition The coalition of the player unit. --- @param #string PlayerUnitCategory The category of the player unit. --- @param #string PlayerUnitType The type of the player unit. --- @param #string TargetUnitName The name of the target unit. --- @param #string TargetUnitCoalition The coalition of the target unit. --- @param #string TargetUnitCategory The category of the target unit. --- @param #string TargetUnitType The type of the target unit. --- @return #SCORING self -function SCORING:ScoreCSV( PlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) - --write statistic information to file - local ScoreTime = self:SecondsToClock( timer.getTime() ) - PlayerName = PlayerName:gsub( '"', '_' ) - - if PlayerUnitName and PlayerUnitName ~= '' then - local PlayerUnit = Unit.getByName( PlayerUnitName ) - - if PlayerUnit then - if not PlayerUnitCategory then - --PlayerUnitCategory = SCORINGCategory[PlayerUnit:getCategory()] - PlayerUnitCategory = _SCORINGCategory[PlayerUnit:getDesc().category] - end - - if not PlayerUnitCoalition then - PlayerUnitCoalition = _SCORINGCoalition[PlayerUnit:getCoalition()] - end - - if not PlayerUnitType then - PlayerUnitType = PlayerUnit:getTypeName() - end - else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' - end - else - PlayerUnitName = '' - PlayerUnitCategory = '' - PlayerUnitCoalition = '' - PlayerUnitType = '' - end - - if not TargetUnitCoalition then - TargetUnitCoalition = '' - end - - if not TargetUnitCategory then - TargetUnitCategory = '' - end - - if not TargetUnitType then - TargetUnitType = '' - end - - if not TargetUnitName then - TargetUnitName = '' - end - - if lfs and io and os then - self.CSVFile:write( - '"' .. self.GameName .. '"' .. ',' .. - '"' .. self.RunTime .. '"' .. ',' .. - '' .. ScoreTime .. '' .. ',' .. - '"' .. PlayerName .. '"' .. ',' .. - '"' .. ScoreType .. '"' .. ',' .. - '"' .. PlayerUnitCoalition .. '"' .. ',' .. - '"' .. PlayerUnitCategory .. '"' .. ',' .. - '"' .. PlayerUnitType .. '"' .. ',' .. - '"' .. PlayerUnitName .. '"' .. ',' .. - '"' .. TargetUnitCoalition .. '"' .. ',' .. - '"' .. TargetUnitCategory .. '"' .. ',' .. - '"' .. TargetUnitType .. '"' .. ',' .. - '"' .. TargetUnitName .. '"' .. ',' .. - '' .. ScoreTimes .. '' .. ',' .. - '' .. ScoreAmount - ) - - self.CSVFile:write( "\n" ) - end -end - - -function SCORING:CloseCSV() - if lfs and io and os then - self.CSVFile:close() - end -end - ---- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area. --- @module CleanUp --- @author Flightcontrol - - - - - - - ---- The CLEANUP class. --- @type CLEANUP --- @extends Core.Base#BASE -CLEANUP = { - ClassName = "CLEANUP", - ZoneNames = {}, - TimeInterval = 300, - CleanUpList = {}, -} - ---- Creates the main object which is handling the cleaning of the debris within the given Zone Names. --- @param #CLEANUP self --- @param #table ZoneNames Is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name. --- @param #number TimeInterval The interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes. --- @return #CLEANUP --- @usage --- -- Clean these Zones. --- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 ) --- or --- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 ) --- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 ) -function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, BASE:New() ) - self:F( { ZoneNames, TimeInterval } ) - - if type( ZoneNames ) == 'table' then - self.ZoneNames = ZoneNames - else - self.ZoneNames = { ZoneNames } - end - if TimeInterval then - self.TimeInterval = TimeInterval - end - - _EVENTDISPATCHER:OnBirth( self._OnEventBirth, self ) - - self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) - - return self -end - - ---- Destroys a group from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSWrapper.Group#Group GroupObject The object to be destroyed. --- @param #string CleanUpGroupName The groupname... -function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName ) - self:F( { GroupObject, CleanUpGroupName } ) - - if GroupObject then -- and GroupObject:isExist() then - trigger.action.deactivateGroup(GroupObject) - self:T( { "GroupObject Destroyed", GroupObject } ) - end -end - ---- Destroys a @{Dcs.DCSWrapper.Unit#Unit} from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSWrapper.Unit#Unit CleanUpUnit The object to be destroyed. --- @param #string CleanUpUnitName The Unit name ... -function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName ) - self:F( { CleanUpUnit, CleanUpUnitName } ) - - if CleanUpUnit then - local CleanUpGroup = Unit.getGroup(CleanUpUnit) - -- TODO Client bug in 1.5.3 - if CleanUpGroup and CleanUpGroup:isExist() then - local CleanUpGroupUnits = CleanUpGroup:getUnits() - if #CleanUpGroupUnits == 1 then - local CleanUpGroupName = CleanUpGroup:getName() - --self:CreateEventCrash( timer.getTime(), CleanUpUnit ) - CleanUpGroup:destroy() - self:T( { "Destroyed Group:", CleanUpGroupName } ) - else - CleanUpUnit:destroy() - self:T( { "Destroyed Unit:", CleanUpUnitName } ) - end - self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list - CleanUpUnit = nil - end - end -end - --- TODO check Dcs.DCSTypes#Weapon ---- Destroys a missile from the simulator, but checks first if it is still existing! --- @param #CLEANUP self --- @param Dcs.DCSTypes#Weapon MissileObject -function CLEANUP:_DestroyMissile( MissileObject ) - self:F( { MissileObject } ) - - if MissileObject and MissileObject:isExist() then - MissileObject:destroy() - self:T( "MissileObject Destroyed") - end -end - -function CLEANUP:_OnEventBirth( Event ) - self:F( { Event } ) - - self.CleanUpList[Event.IniDCSUnitName] = {} - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName - - _EVENTDISPATCHER:OnEngineShutDownForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnEngineStartUpForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnHitForUnit( Event.IniDCSUnitName, self._EventAddForCleanUp, self ) - _EVENTDISPATCHER:OnPilotDeadForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnDeadForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnCrashForUnit( Event.IniDCSUnitName, self._EventCrash, self ) - _EVENTDISPATCHER:OnShotForUnit( Event.IniDCSUnitName, self._EventShot, self ) - - --self:AddEvent( world.event.S_EVENT_ENGINE_SHUTDOWN, self._EventAddForCleanUp ) - --self:AddEvent( world.event.S_EVENT_ENGINE_STARTUP, self._EventAddForCleanUp ) --- self:AddEvent( world.event.S_EVENT_HIT, self._EventAddForCleanUp ) -- , self._EventHitCleanUp ) --- self:AddEvent( world.event.S_EVENT_CRASH, self._EventCrash ) -- , self._EventHitCleanUp ) --- --self:AddEvent( world.event.S_EVENT_DEAD, self._EventCrash ) --- self:AddEvent( world.event.S_EVENT_SHOT, self._EventShot ) --- --- self:EnableEvents() - - -end - ---- Detects if a crash event occurs. --- Crashed units go into a CleanUpList for removal. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventCrash( Event ) - self:F( { Event } ) - - --TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed. - -- self:T("before getGroup") - -- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired - -- self:T("after getGroup") - -- _grp:destroy() - -- self:T("after deactivateGroup") - -- event.initiator:destroy() - - self.CleanUpList[Event.IniDCSUnitName] = {} - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup - self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName - self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName - -end - ---- Detects if a unit shoots a missile. --- If this occurs within one of the zones, then the weapon used must be destroyed. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventShot( Event ) - self:F( { Event } ) - - -- Test if the missile was fired within one of the CLEANUP.ZoneNames. - local CurrentLandingZoneID = 0 - CurrentLandingZoneID = routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) - if ( CurrentLandingZoneID ) then - -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. - --_SEADmissile:destroy() - SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) - end -end - - ---- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventHitCleanUp( Event ) - self:F( { Event } ) - - if Event.IniDCSUnit then - if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then - self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniDCSUnit:getLife(), "/", Event.IniDCSUnit:getLife0() } ) - if Event.IniDCSUnit:getLife() < Event.IniDCSUnit:getLife0() then - self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName ) - SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) - end - end - end - - if Event.TgtDCSUnit then - if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then - self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtDCSUnit:getLife(), "/", Event.TgtDCSUnit:getLife0() } ) - if Event.TgtDCSUnit:getLife() < Event.TgtDCSUnit:getLife0() then - self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName ) - SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) - end - end - end -end - ---- Add the @{Dcs.DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp. -function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName ) - self:F( { CleanUpUnit, CleanUpUnitName } ) - - self.CleanUpList[CleanUpUnitName] = {} - self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit - self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName - self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit) - self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName() - self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime() - self.CleanUpList[CleanUpUnitName].CleanUpMoved = false - - self:T( { "CleanUp: Add to CleanUpList: ", Unit.getGroup(CleanUpUnit):getName(), CleanUpUnitName } ) - -end - ---- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List. --- @param #CLEANUP self --- @param Dcs.DCSTypes#Event event -function CLEANUP:_EventAddForCleanUp( Event ) - - if Event.IniDCSUnit then - if self.CleanUpList[Event.IniDCSUnitName] == nil then - if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then - self:_AddForCleanUp( Event.IniDCSUnit, Event.IniDCSUnitName ) - end - end - end - - if Event.TgtDCSUnit then - if self.CleanUpList[Event.TgtDCSUnitName] == nil then - if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then - self:_AddForCleanUp( Event.TgtDCSUnit, Event.TgtDCSUnitName ) - end - end - end - -end - -local CleanUpSurfaceTypeText = { - "LAND", - "SHALLOW_WATER", - "WATER", - "ROAD", - "RUNWAY" - } - ---- At the defined time interval, CleanUp the Groups within the CleanUpList. --- @param #CLEANUP self -function CLEANUP:_CleanUpScheduler() - self:F( { "CleanUp Scheduler" } ) - - local CleanUpCount = 0 - for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do - CleanUpCount = CleanUpCount + 1 - - self:T( { CleanUpUnitName, UnitData } ) - local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName) - local CleanUpGroupName = UnitData.CleanUpGroupName - local CleanUpUnitName = UnitData.CleanUpUnitName - if CleanUpUnit then - self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } ) - if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then - local CleanUpUnitVec3 = CleanUpUnit:getPoint() - --self:T( CleanUpUnitVec3 ) - local CleanUpUnitVec2 = {} - CleanUpUnitVec2.x = CleanUpUnitVec3.x - CleanUpUnitVec2.y = CleanUpUnitVec3.z - --self:T( CleanUpUnitVec2 ) - local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2) - --self:T( CleanUpSurfaceType ) - - if CleanUpUnit and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then - if CleanUpSurfaceType == land.SurfaceType.RUNWAY then - if CleanUpUnit:inAir() then - local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2) - local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight - self:T( { "CleanUp Scheduler", "Height = " .. CleanUpUnitHeight } ) - if CleanUpUnitHeight < 30 then - self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - else - self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - end - end - -- Clean Units which are waiting for a very long time in the CleanUpZone. - if CleanUpUnit then - local CleanUpUnitVelocity = CleanUpUnit:getVelocity() - local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z) - if CleanUpUnitVelocityTotal < 1 then - if UnitData.CleanUpMoved then - if UnitData.CleanUpTime + 180 <= timer.getTime() then - self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } ) - self:_DestroyUnit(CleanUpUnit, CleanUpUnitName) - end - end - else - UnitData.CleanUpTime = timer.getTime() - UnitData.CleanUpMoved = true - end - end - - else - -- Do nothing ... - self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE - end - else - self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." ) - self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE - end - end - self:T(CleanUpCount) - - return true -end - ---- This module contains the SPAWN class. --- --- # 1) @{Functional.Spawn#SPAWN} class, extends @{Core.Base#BASE} --- --- The @{#SPAWN} class allows to spawn dynamically new groups, based on pre-defined initialization settings, modifying the behaviour when groups are spawned. --- For each group to be spawned, within the mission editor, a group has to be created with the "late activation flag" set. We call this group the *"Spawn Template"* of the SPAWN object. --- A reference to this Spawn Template needs to be provided when constructing the SPAWN object, by indicating the name of the group within the mission editor in the constructor methods. --- --- Within the SPAWN object, there is an internal index that keeps track of which group from the internal group list was spawned. --- When new groups get spawned by using the SPAWN methods (see below), it will be validated whether the Limits (@{#SPAWN.Limit}) of the SPAWN object are not reached. --- When all is valid, a new group will be created by the spawning methods, and the internal index will be increased with 1. --- --- Regarding the name of new spawned groups, a _SpawnPrefix_ will be assigned for each new group created. --- If you want to have the Spawn Template name to be used as the _SpawnPrefix_ name, use the @{#SPAWN.New} constructor. --- However, when the @{#SPAWN.NewWithAlias} constructor was used, the Alias name will define the _SpawnPrefix_ name. --- Groups will follow the following naming structure when spawned at run-time: --- --- 1. Spawned groups will have the name _SpawnPrefix_#ggg, where ggg is a counter from 0 to 999. --- 2. Spawned units will have the name _SpawnPrefix_#ggg-uu, where uu is a counter from 0 to 99 for each new spawned unit belonging to the group. --- --- Some additional notes that need to be remembered: --- --- * Templates are actually groups defined within the mission editor, with the flag "Late Activation" set. As such, these groups are never used within the mission, but are used by the @{#SPAWN} module. --- * It is important to defined BEFORE you spawn new groups, a proper initialization of the SPAWN instance is done with the options you want to use. --- * When designing a mission, NEVER name groups using a "#" within the name of the group Spawn Template(s), or the SPAWN module logic won't work anymore. --- --- ## 1.1) SPAWN construction methods --- --- Create a new SPAWN object with the @{#SPAWN.New}() or the @{#SPAWN.NewWithAlias}() methods: --- --- * @{#SPAWN.New}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition). --- * @{#SPAWN.NewWithAlias}(): Creates a new SPAWN object taking the name of the group that represents the GROUP Template (definition), and gives each spawned @{Group} an different name. --- --- It is important to understand how the SPAWN class works internally. The SPAWN object created will contain internally a list of groups that will be spawned and that are already spawned. --- The initialization methods will modify this list of groups so that when a group gets spawned, ALL information is already prepared when spawning. This is done for performance reasons. --- So in principle, the group list will contain all parameters and configurations after initialization, and when groups get actually spawned, this spawning can be done quickly and efficient. --- --- ## 1.2) SPAWN initialization methods --- --- A spawn object will behave differently based on the usage of **initialization** methods, which all start with the **Init** prefix: --- --- * @{#SPAWN.InitLimit}(): Limits the amount of groups that can be alive at the same time and that can be dynamically spawned. --- * @{#SPAWN.InitRandomizeRoute}(): Randomize the routes of spawned groups, and for air groups also optionally the height. --- * @{#SPAWN.InitRandomizeTemplate}(): Randomize the group templates so that when a new group is spawned, a random group template is selected from one of the templates defined. --- * @{#SPAWN.InitUncontrolled}(): Spawn plane groups uncontrolled. --- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a batallion in an array. --- * @{#SPAWN.InitRepeat}(): Re-spawn groups when they land at the home base. Similar methods are @{#SPAWN.InitRepeatOnLanding} and @{#SPAWN.InitRepeatOnEngineShutDown}. --- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Unit}s in the @{Group} that is spawned within a **radius band**, given an Outer and Inner radius. --- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor. --- --- ## 1.3) SPAWN spawning methods --- --- Groups can be spawned at different times and methods: --- --- * @{#SPAWN.Spawn}(): Spawn one new group based on the last spawned index. --- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index. --- * @{#SPAWN.SpawnScheduled}(): Spawn groups at scheduled but randomized intervals. You can use @{#SPAWN.SpawnScheduleStart}() and @{#SPAWN.SpawnScheduleStop}() to start and stop the schedule respectively. --- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air). --- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ). --- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}. --- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}. --- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}. --- --- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object. --- You can use the @{GROUP} object to do further actions with the DCSGroup. --- --- ## 1.4) Retrieve alive GROUPs spawned by the SPAWN object --- --- The SPAWN class administers which GROUPS it has reserved (in stock) or has created during mission execution. --- Every time a SPAWN object spawns a new GROUP object, a reference to the GROUP object is added to an internal table of GROUPS. --- SPAWN provides methods to iterate through that internal GROUP object reference table: --- --- * @{#SPAWN.GetFirstAliveGroup}(): Will find the first alive GROUP it has spawned, and return the alive GROUP object and the first Index where the first alive GROUP object has been found. --- * @{#SPAWN.GetNextAliveGroup}(): Will find the next alive GROUP object from a given Index, and return a reference to the alive GROUP object and the next Index where the alive GROUP has been found. --- * @{#SPAWN.GetLastAliveGroup}(): Will find the last alive GROUP object, and will return a reference to the last live GROUP object and the last Index where the last alive GROUP object has been found. --- --- You can use the methods @{#SPAWN.GetFirstAliveGroup}() and sequently @{#SPAWN.GetNextAliveGroup}() to iterate through the alive GROUPS within the SPAWN object, and to actions... See the respective methods for an example. --- The method @{#SPAWN.GetGroupFromIndex}() will return the GROUP object reference from the given Index, dead or alive... --- --- ## 1.5) SPAWN object cleaning --- --- Sometimes, it will occur during a mission run-time, that ground or especially air objects get damaged, and will while being damged stop their activities, while remaining alive. --- In such cases, the SPAWN object will just sit there and wait until that group gets destroyed, but most of the time it won't, --- and it may occur that no new groups are or can be spawned as limits are reached. --- To prevent this, a @{#SPAWN.InitCleanUp}() initialization method has been defined that will silently monitor the status of each spawned group. --- Once a group has a velocity = 0, and has been waiting for a defined interval, that group will be cleaned or removed from run-time. --- There is a catch however :-) If a damaged group has returned to an airbase within the coalition, that group will not be considered as "lost"... --- In such a case, when the inactive group is cleaned, a new group will Re-spawned automatically. --- This models AI that has succesfully returned to their airbase, to restart their combat activities. --- Check the @{#SPAWN.InitCleanUp}() for further info. --- --- ## 1.6) Catch the @{Group} spawn event in a callback function! --- --- When using the SpawnScheduled method, new @{Group}s are created following the schedule timing parameters. --- When a new @{Group} is spawned, you maybe want to execute actions with that group spawned at the spawn event. --- To SPAWN class supports this functionality through the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method, which takes a function as a parameter that you can define locally. --- Whenever a new @{Group} is spawned, the given function is called, and the @{Group} that was just spawned, is given as a parameter. --- As a result, your spawn event handling function requires one parameter to be declared, which will contain the spawned @{Group} object. --- A coding example is provided at the description of the @{#SPAWN.OnSpawnGroup}( **function( SpawnedGroup ) end ** ) method. --- --- ==== --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-15: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-15: SPAWN:**InitRandomizeZones( SpawnZones )** added. --- --- * This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. --- --- 2016-08-14: SPAWN:**OnSpawnGroup**( SpawnCallBackFunction, ... ) replaces SPAWN:_SpawnFunction_( SpawnCallBackFunction, ... ). --- --- 2016-08-14: SPAWN.SpawnInZone( Zone, __RandomizeGroup__, SpawnIndex ) replaces SpawnInZone( Zone, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ). --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromVec3( Vec3, SpawnIndex ) replaces SpawnFromVec3( Vec3, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromVec2( Vec2, SpawnIndex ) replaces SpawnFromVec2( Vec2, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromUnit( SpawnUnit, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.SpawnFromUnit( SpawnUnit, SpawnIndex ) replaces SpawnFromStatic( SpawnStatic, _RandomizeUnits, OuterRadius, InnerRadius,_ SpawnIndex ): --- --- * The RandomizeUnits, OuterRadius and InnerRadius have been replaced with a new method @{#SPAWN.InitRandomizeUnits}( RandomizeUnits, OuterRadius, InnerRadius ). --- * A new parameter RandomizeGroup to reflect the randomization of the starting position of the Spawned @{Group}. --- --- 2016-08-14: SPAWN.**InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius )** added: --- --- * This method enables the randomization of units at the first route point in a radius band at a spawn event. --- --- 2016-08-14: SPAWN.**Init**Limit( SpawnMaxUnitsAlive, SpawnMaxGroups ) replaces SPAWN._Limit_( SpawnMaxUnitsAlive, SpawnMaxGroups ): --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**Array( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) replaces SPAWN._Array_( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) replaces SPAWN._RandomizeRoute_( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**RandomizeTemplate( SpawnTemplatePrefixTable ) replaces SPAWN._RandomizeTemplate_( SpawnTemplatePrefixTable ). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- 2016-08-14: SPAWN.**Init**UnControlled() replaces SPAWN._UnControlled_(). --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * **Aaron**: Posed the idea for Group position randomization at SpawnInZone and make the Unit randomization separate from the Group randomization. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming --- --- @module Spawn - - - ---- SPAWN Class --- @type SPAWN --- @extends Core.Base#BASE --- @field ClassName --- @field #string SpawnTemplatePrefix --- @field #string SpawnAliasPrefix --- @field #number AliveUnits --- @field #number MaxAliveUnits --- @field #number SpawnIndex --- @field #number MaxAliveGroups --- @field #SPAWN.SpawnZoneTable SpawnZoneTable -SPAWN = { - ClassName = "SPAWN", - SpawnTemplatePrefix = nil, - SpawnAliasPrefix = nil, -} - - ---- @type SPAWN.SpawnZoneTable --- @list SpawnZone - - ---- Creates the main object to spawn a @{Group} defined in the DCS ME. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ) --- @usage local Plane = SPAWN:New( "Plane" ) -- Creates a new local variable that can initiate new planes with the name "Plane#ddd" using the template "Plane" as defined within the ME. -function SPAWN:New( SpawnTemplatePrefix ) - local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN - self:F( { SpawnTemplatePrefix } ) - - local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) - if TemplateGroup then - self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.SpawnIndex = 0 - self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. - self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - - self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. - else - error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) - end - - return self -end - ---- Creates a new SPAWN instance to create new groups based on the defined template and using a new alias for each new group. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. --- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' ) --- @usage local PlaneWithAlias = SPAWN:NewWithAlias( "Plane", "Bomber" ) -- Creates a new local variable that can instantiate new planes with the name "Bomber#ddd" using the template "Plane" as defined within the ME. -function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } ) - - local TemplateGroup = Group.getByName( SpawnTemplatePrefix ) - if TemplateGroup then - self.SpawnTemplatePrefix = SpawnTemplatePrefix - self.SpawnAliasPrefix = SpawnAliasPrefix - self.SpawnIndex = 0 - self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart. - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.SpawnIsScheduled = false -- Reflects if the spawning for this SpawnTemplatePrefix is going to be scheduled or not. - self.SpawnTemplate = self._GetTemplate( self, SpawnTemplatePrefix ) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!! - self.Repeat = false -- Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning. - self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts. - self.SpawnMaxUnitsAlive = 0 -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned. - self.SpawnRandomize = false -- Sets the randomization flag of new Spawned units to false. - self.SpawnVisible = false -- Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned. - - self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. - else - error( "SPAWN:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" ) - end - - return self -end - - ---- Limits the Maximum amount of Units that can be alive at the same time, and the maximum amount of groups that can be spawned. --- Note that this method is exceptionally important to balance the performance of the mission. Depending on the machine etc, a mission can only process a maximum amount of units. --- If the time interval must be short, but there should not be more Units or Groups alive than a maximum amount of units, then this method should be used... --- When a @{#SPAWN.New} is executed and the limit of the amount of units alive is reached, then no new spawn will happen of the group, until some of these units of the spawn object will be destroyed. --- @param #SPAWN self --- @param #number SpawnMaxUnitsAlive The maximum amount of units that can be alive at runtime. --- @param #number SpawnMaxGroups The maximum amount of groups that can be spawned. When the limit is reached, then no more actual spawns will happen of the group. --- This parameter is useful to define a maximum amount of airplanes, ground troops, helicopters, ships etc within a supply area. --- This parameter accepts the value 0, which defines that there are no maximum group limits, but there are limits on the maximum of units that can be alive at the same time. --- @return #SPAWN self --- @usage --- -- NATO helicopters engaging in the battle field. --- -- This helicopter group consists of one Unit. So, this group will SPAWN maximum 2 groups simultaneously within the DCSRTE. --- -- There will be maximum 24 groups spawned during the whole mission lifetime. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitLimit( 2, 24 ) -function SPAWN:InitLimit( SpawnMaxUnitsAlive, SpawnMaxGroups ) - self:F( { self.SpawnTemplatePrefix, SpawnMaxUnitsAlive, SpawnMaxGroups } ) - - self.SpawnMaxUnitsAlive = SpawnMaxUnitsAlive -- The maximum amount of groups that can be alive of SpawnTemplatePrefix at the same time. - self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned. - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_InitializeSpawnGroups( SpawnGroupID ) - end - - return self -end - - ---- Randomizes the defined route of the SpawnTemplatePrefix group in the ME. This is very useful to define extra variation of the behaviour of groups. --- @param #SPAWN self --- @param #number SpawnStartPoint is the waypoint where the randomization begins. --- Note that the StartPoint = 0 equaling the point where the group is spawned. --- @param #number SpawnEndPoint is the waypoint where the randomization ends counting backwards. --- This parameter is useful to avoid randomization to end at a waypoint earlier than the last waypoint on the route. --- @param #number SpawnRadius is the radius in meters in which the randomization of the new waypoints, with the original waypoint of the original template located in the middle ... --- @param #number SpawnHeight (optional) Specifies the **additional** height in meters that can be added to the base height specified at each waypoint in the ME. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). --- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. --- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) -function SPAWN:InitRandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight ) - self:F( { self.SpawnTemplatePrefix, SpawnStartPoint, SpawnEndPoint, SpawnRadius, SpawnHeight } ) - - self.SpawnRandomizeRoute = true - self.SpawnRandomizeRouteStartPoint = SpawnStartPoint - self.SpawnRandomizeRouteEndPoint = SpawnEndPoint - self.SpawnRandomizeRouteRadius = SpawnRadius - self.SpawnRandomizeRouteHeight = SpawnHeight - - for GroupID = 1, self.SpawnMaxGroups do - self:_RandomizeRoute( GroupID ) - end - - return self -end - ---- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius. --- @param #SPAWN self --- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius. --- @param Dcs.DCSTypes#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned. --- @param Dcs.DCSTypes#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned. --- @return #SPAWN --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The KA-50 has waypoints Start point ( =0 or SP ), 1, 2, 3, 4, End point (= 5 or DP). --- -- Waypoints 2 and 3 will only be randomized. The others will remain on their original position with each new spawn of the helicopter. --- -- The randomization of waypoint 2 and 3 will take place within a radius of 2000 meters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):InitRandomizeRoute( 2, 2, 2000 ) -function SPAWN:InitRandomizeUnits( RandomizeUnits, OuterRadius, InnerRadius ) - self:F( { self.SpawnTemplatePrefix, RandomizeUnits, OuterRadius, InnerRadius } ) - - self.SpawnRandomizeUnits = RandomizeUnits or false - self.SpawnOuterRadius = OuterRadius or 0 - self.SpawnInnerRadius = InnerRadius or 0 - - for GroupID = 1, self.SpawnMaxGroups do - self:_RandomizeRoute( GroupID ) - end - - return self -end - ---- This method is rather complicated to understand. But I'll try to explain. --- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor, --- but they will all follow the same Template route and have the same prefix name. --- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group. --- @param #SPAWN self --- @param #string SpawnTemplatePrefixTable A table with the names of the groups defined within the mission editor, from which one will be choosen when a new group will be spawned. --- @return #SPAWN --- @usage --- -- NATO Tank Platoons invading Gori. --- -- Choose between 13 different 'US Tank Platoon' configurations for each new SPAWN the Group to be spawned for the --- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SpawnTemplatePrefixes. --- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and --- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission. --- Spawn_US_Platoon = { 'US Tank Platoon 1', 'US Tank Platoon 2', 'US Tank Platoon 3', 'US Tank Platoon 4', 'US Tank Platoon 5', --- 'US Tank Platoon 6', 'US Tank Platoon 7', 'US Tank Platoon 8', 'US Tank Platoon 9', 'US Tank Platoon 10', --- 'US Tank Platoon 11', 'US Tank Platoon 12', 'US Tank Platoon 13' } --- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) --- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) --- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplate( Spawn_US_Platoon ):InitRandomizeRoute( 3, 3, 2000 ) -function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable ) - self:F( { self.SpawnTemplatePrefix, SpawnTemplatePrefixTable } ) - - self.SpawnTemplatePrefixTable = SpawnTemplatePrefixTable - self.SpawnRandomizeTemplate = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_RandomizeTemplate( SpawnGroupID ) - end - - return self -end - ---TODO: Add example. ---- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. --- @param #SPAWN self --- @param #table SpawnZoneTable A table with @{Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Zone}s objects. --- @return #SPAWN --- @usage --- -- NATO Tank Platoons invading Gori. --- -- Choose between 3 different zones for each new SPAWN the Group to be executed, regardless of the zone type. -function SPAWN:InitRandomizeZones( SpawnZoneTable ) - self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } ) - - self.SpawnZoneTable = SpawnZoneTable - self.SpawnRandomizeZones = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:_RandomizeZones( SpawnGroupID ) - end - - return self -end - - - - - ---- For planes and helicopters, when these groups go home and land on their home airbases and farps, they normally would taxi to the parking spot, shut-down their engines and wait forever until the Group is removed by the runtime environment. --- This method is used to re-spawn automatically (so no extra call is needed anymore) the same group after it has landed. --- This will enable a spawned group to be re-spawned after it lands, until it is destroyed... --- Note: When the group is respawned, it will re-spawn from the original airbase where it took off. --- So ensure that the routes for groups that respawn, always return to the original airbase, or players may get confused ... --- @param #SPAWN self --- @return #SPAWN self --- @usage --- -- RU Su-34 - AI Ship Attack --- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically. --- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():InitRandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown() -function SPAWN:InitRepeat() - self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } ) - - self.Repeat = true - self.RepeatOnEngineShutDown = false - self.RepeatOnLanding = true - - return self -end - ---- Respawn group after landing. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitRepeatOnLanding() - self:F( { self.SpawnTemplatePrefix } ) - - self:InitRepeat() - self.RepeatOnEngineShutDown = false - self.RepeatOnLanding = true - - return self -end - - ---- Respawn after landing when its engines have shut down. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitRepeatOnEngineShutDown() - self:F( { self.SpawnTemplatePrefix } ) - - self:InitRepeat() - self.RepeatOnEngineShutDown = true - self.RepeatOnLanding = false - - return self -end - - ---- CleanUp groups when they are still alive, but inactive. --- When groups are still alive and have become inactive due to damage and are unable to contribute anything, then this group will be removed at defined intervals in seconds. --- @param #SPAWN self --- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds. --- @return #SPAWN self --- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive. -function SPAWN:InitCleanUp( SpawnCleanUpInterval ) - self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } ) - - self.SpawnCleanUpInterval = SpawnCleanUpInterval - self.SpawnCleanUpTimeStamps = {} - - local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() - self:T( { "CleanUp Scheduler:", SpawnGroup } ) - - --self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, SpawnCleanUpInterval ) - self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 ) - return self -end - - - ---- Makes the groups visible before start (like a batallion). --- The method will take the position of the group as the first position in the array. --- @param #SPAWN self --- @param #number SpawnAngle The angle in degrees how the groups and each unit of the group will be positioned. --- @param #number SpawnWidth The amount of Groups that will be positioned on the X axis. --- @param #number SpawnDeltaX The space between each Group on the X-axis. --- @param #number SpawnDeltaY The space between each Group on the Y-axis. --- @return #SPAWN self --- @usage --- -- Define an array of Groups. --- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):InitLimit( 2, 24 ):InitArray( 90, "Diamond", 10, 100, 50 ) -function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY ) - self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } ) - - self.SpawnVisible = true -- When the first Spawn executes, all the Groups need to be made visible before start. - - local SpawnX = 0 - local SpawnY = 0 - local SpawnXIndex = 0 - local SpawnYIndex = 0 - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self:T( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } ) - - self.SpawnGroups[SpawnGroupID].Visible = true - self.SpawnGroups[SpawnGroupID].Spawned = false - - SpawnXIndex = SpawnXIndex + 1 - if SpawnWidth and SpawnWidth ~= 0 then - if SpawnXIndex >= SpawnWidth then - SpawnXIndex = 0 - SpawnYIndex = SpawnYIndex + 1 - end - end - - local SpawnRootX = self.SpawnGroups[SpawnGroupID].SpawnTemplate.x - local SpawnRootY = self.SpawnGroups[SpawnGroupID].SpawnTemplate.y - - self:_TranslateRotate( SpawnGroupID, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - - self.SpawnGroups[SpawnGroupID].SpawnTemplate.lateActivation = true - self.SpawnGroups[SpawnGroupID].SpawnTemplate.visible = true - - self.SpawnGroups[SpawnGroupID].Visible = true - - _EVENTDISPATCHER:OnBirthForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnBirth, self ) - _EVENTDISPATCHER:OnCrashForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnDeadOrCrash, self ) - - if self.Repeat then - _EVENTDISPATCHER:OnTakeOffForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnTakeOff, self ) - _EVENTDISPATCHER:OnLandForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnLand, self ) - end - if self.RepeatOnEngineShutDown then - _EVENTDISPATCHER:OnEngineShutDownForTemplate( self.SpawnGroups[SpawnGroupID].SpawnTemplate, self._OnEngineShutDown, self ) - end - - self.SpawnGroups[SpawnGroupID].Group = _DATABASE:Spawn( self.SpawnGroups[SpawnGroupID].SpawnTemplate ) - - SpawnX = SpawnXIndex * SpawnDeltaX - SpawnY = SpawnYIndex * SpawnDeltaY - end - - return self -end - - - ---- Will spawn a group based on the internal index. --- Note: Uses @{DATABASE} module defined in MOOSE. --- @param #SPAWN self --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:Spawn() - self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, self.AliveUnits } ) - - return self:SpawnWithIndex( self.SpawnIndex + 1 ) -end - ---- Will re-spawn a group based on a given index. --- Note: Uses @{DATABASE} module defined in MOOSE. --- @param #SPAWN self --- @param #string SpawnIndex The index of the group to be spawned. --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:ReSpawn( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) - - if not SpawnIndex then - SpawnIndex = 1 - end - --- TODO: This logic makes DCS crash and i don't know why (yet). - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - local WayPoints = SpawnGroup and SpawnGroup.WayPoints or nil - if SpawnGroup then - local SpawnDCSGroup = SpawnGroup:GetDCSObject() - if SpawnDCSGroup then - SpawnGroup:Destroy() - end - end - - local SpawnGroup = self:SpawnWithIndex( SpawnIndex ) - if SpawnGroup and WayPoints then - -- If there were WayPoints set, then Re-Execute those WayPoints! - self:E( WayPoints ) - SpawnGroup:WayPointInitialize( WayPoints ) - SpawnGroup:WayPointExecute( 1, 5 ) - end - - return SpawnGroup -end - ---- Will spawn a group with a specified index number. --- Uses @{DATABASE} global object defined in MOOSE. --- @param #SPAWN self --- @param #string SpawnIndex The index of the group to be spawned. --- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions. -function SPAWN:SpawnWithIndex( SpawnIndex ) - self:F2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } ) - - if self:_GetSpawnIndex( SpawnIndex ) then - - if self.SpawnGroups[self.SpawnIndex].Visible then - self.SpawnGroups[self.SpawnIndex].Group:Activate() - else - - local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate - self:T( SpawnTemplate.name ) - - if SpawnTemplate then - - local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y ) - self:T( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } ) - - -- If RandomizeUnits, then Randomize the formation at the start point. - if self.SpawnRandomizeUnits then - for UnitID = 1, #SpawnTemplate.units do - local RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius ) - SpawnTemplate.units[UnitID].x = RandomVec2.x - SpawnTemplate.units[UnitID].y = RandomVec2.y - self:T( 'SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - end - end - end - - _EVENTDISPATCHER:OnBirthForTemplate( SpawnTemplate, self._OnBirth, self ) - _EVENTDISPATCHER:OnCrashForTemplate( SpawnTemplate, self._OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForTemplate( SpawnTemplate, self._OnDeadOrCrash, self ) - - if self.Repeat then - _EVENTDISPATCHER:OnTakeOffForTemplate( SpawnTemplate, self._OnTakeOff, self ) - _EVENTDISPATCHER:OnLandForTemplate( SpawnTemplate, self._OnLand, self ) - end - if self.RepeatOnEngineShutDown then - _EVENTDISPATCHER:OnEngineShutDownForTemplate( SpawnTemplate, self._OnEngineShutDown, self ) - end - self:T3( SpawnTemplate.name ) - - self.SpawnGroups[self.SpawnIndex].Group = _DATABASE:Spawn( SpawnTemplate ) - - -- If there is a SpawnFunction hook defined, call it. - if self.SpawnFunctionHook then - self.SpawnFunctionHook( self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments ) ) - end - -- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats. - --if self.Repeat then - -- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" ) - --end - end - - self.SpawnGroups[self.SpawnIndex].Spawned = true - return self.SpawnGroups[self.SpawnIndex].Group - else - --self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } ) - end - - return nil -end - ---- Spawns new groups at varying time intervals. --- This is useful if you want to have continuity within your missions of certain (AI) groups to be present (alive) within your missions. --- @param #SPAWN self --- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups. --- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn. --- The variation is a number between 0 and 1, representing the %-tage of variation to be applied on the time interval. --- @return #SPAWN self --- @usage --- -- NATO helicopters engaging in the battle field. --- -- The time interval is set to SPAWN new helicopters between each 600 seconds, with a time variation of 50%. --- -- The time variation in this case will be between 450 seconds and 750 seconds. --- -- This is calculated as follows: --- -- Low limit: 600 * ( 1 - 0.5 / 2 ) = 450 --- -- High limit: 600 * ( 1 + 0.5 / 2 ) = 750 --- -- Between these two values, a random amount of seconds will be choosen for each new spawn of the helicopters. --- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation ) - self:F( { SpawnTime, SpawnTimeVariation } ) - - if SpawnTime ~= nil and SpawnTimeVariation ~= nil then - self.SpawnScheduler = SCHEDULER:New( self, self._Scheduler, {}, 1, SpawnTime, SpawnTimeVariation ) - end - - return self -end - ---- Will re-start the spawning scheduler. --- Note: This method is only required to be called when the schedule was stopped. -function SPAWN:SpawnScheduleStart() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnScheduler:Start() -end - ---- Will stop the scheduled spawning scheduler. -function SPAWN:SpawnScheduleStop() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnScheduler:Stop() -end - - ---- Allows to place a CallFunction hook when a new group spawns. --- The provided method will be called when a new group is spawned, including its given parameters. --- The first parameter of the SpawnFunction is the @{Wrapper.Group#GROUP} that was spawned. --- @param #SPAWN self --- @param #function SpawnCallBackFunction The function to be called when a group spawns. --- @param SpawnFunctionArguments A random amount of arguments to be provided to the function when the group spawns. --- @return #SPAWN --- @usage --- -- Declare SpawnObject and call a function when a new Group is spawned. --- local SpawnObject = SPAWN --- :New( "SpawnObject" ) --- :InitLimit( 2, 10 ) --- :OnSpawnGroup( --- function( SpawnGroup ) --- SpawnGroup:E( "I am spawned" ) --- end --- ) --- :SpawnScheduled( 300, 0.3 ) -function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... ) - self:F( "OnSpawnGroup" ) - - self.SpawnFunctionHook = SpawnCallBackFunction - self.SpawnFunctionArguments = {} - if arg then - self.SpawnFunctionArguments = arg - end - - return self -end - - ---- Will spawn a group from a Vec3 in 3D space. --- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 coordinates where to spawn the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromVec3( Vec3, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } ) - - local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) - self:T2(PointVec3) - - if SpawnIndex then - else - SpawnIndex = self.SpawnIndex + 1 - end - - if self:_GetSpawnIndex( SpawnIndex ) then - - local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate - - if SpawnTemplate then - - self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } ) - - -- Translate the position of the Group Template to the Vec3. - for UnitID = 1, #SpawnTemplate.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - local UnitTemplate = SpawnTemplate.units[UnitID] - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = Vec3.x + ( SX - BX ) - local TY = Vec3.z + ( SY - BY ) - SpawnTemplate.units[UnitID].x = TX - SpawnTemplate.units[UnitID].y = TY - SpawnTemplate.units[UnitID].alt = Vec3.y - self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) - end - - SpawnTemplate.route.points[1].x = Vec3.x - SpawnTemplate.route.points[1].y = Vec3.z - SpawnTemplate.route.points[1].alt = Vec3.y - - SpawnTemplate.x = Vec3.x - SpawnTemplate.y = Vec3.z - - return self:SpawnWithIndex( self.SpawnIndex ) - end - end - - return nil -end - ---- Will spawn a group from a Vec2 in 3D space. --- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromVec2( Vec2, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } ) - - local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 ) - return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex ) -end - - ---- Will spawn a group from a hosting unit. This method is mostly advisable to be used if you want to simulate spawning from air units, like helicopters, which are dropping infantry into a defined Landing Zone. --- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } ) - - if HostUnit and HostUnit:IsAlive() then -- and HostUnit:getUnit(1):inAir() == false then - return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex ) - end - - return nil -end - ---- Will spawn a group from a hosting static. This method is mostly advisable to be used if you want to simulate spawning from buldings and structures (static buildings). --- You can use the returned group to further define the route to be followed. --- @param #SPAWN self --- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil Nothing was spawned. -function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } ) - - if HostStatic and HostStatic:IsAlive() then - return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex ) - end - - return nil -end - ---- Will spawn a Group within a given @{Zone}. --- The @{Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}. --- Once the @{Group} is spawned within the zone, the @{Group} will continue on its route. --- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates. --- @param #SPAWN self --- @param Core.Zone#ZONE Zone The zone where the group is to be spawned. --- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone. --- @param #number SpawnIndex (optional) The index which group to spawn within the given zone. --- @return Wrapper.Group#GROUP that was spawned. --- @return #nil when nothing was spawned. -function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } ) - - if Zone then - if RandomizeGroup then - return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex ) - else - return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex ) - end - end - - return nil -end - ---- (AIR) Will spawn a plane group in uncontrolled mode... --- This will be similar to the uncontrolled flag setting in the ME. --- @param #SPAWN self --- @return #SPAWN self -function SPAWN:InitUnControlled() - self:F( { self.SpawnTemplatePrefix } ) - - self.SpawnUnControlled = true - - for SpawnGroupID = 1, self.SpawnMaxGroups do - self.SpawnGroups[SpawnGroupID].UnControlled = true - end - - return self -end - - - ---- Will return the SpawnGroupName either with with a specific count number or without any count. --- @param #SPAWN self --- @param #number SpawnIndex Is the number of the Group that is to be spawned. --- @return #string SpawnGroupName -function SPAWN:SpawnGroupName( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex } ) - - local SpawnPrefix = self.SpawnTemplatePrefix - if self.SpawnAliasPrefix then - SpawnPrefix = self.SpawnAliasPrefix - end - - if SpawnIndex then - local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex ) - self:T( SpawnName ) - return SpawnName - else - self:T( SpawnPrefix ) - return SpawnPrefix - end - -end - ---- Will find the first alive @{Group} it has spawned, and return the alive @{Group} object and the first Index where the first alive @{Group} object has been found. --- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The @{Group} object found, the new Index where the group was found. --- @return #nil, #nil When no group is found, #nil is returned. --- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() --- while GroupPlane ~= nil do --- -- Do actions with the GroupPlane object. --- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) --- end -function SPAWN:GetFirstAliveGroup() - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - for SpawnIndex = 1, self.SpawnCount do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - return SpawnGroup, SpawnIndex - end - end - - return nil, nil -end - - ---- Will find the next alive @{Group} object from a given Index, and return a reference to the alive @{Group} object and the next Index where the alive @{Group} has been found. --- @param #SPAWN self --- @param #number SpawnIndexStart A Index holding the start position to search from. This method can also be used to find the first alive @{Group} object from the given Index. --- @return Wrapper.Group#GROUP, #number The next alive @{Group} object found, the next Index where the next alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found from the start Index position, #nil is returned. --- @usage --- -- Find the first alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetFirstAliveGroup() --- while GroupPlane ~= nil do --- -- Do actions with the GroupPlane object. --- GroupPlane, Index = SpawnPlanes:GetNextAliveGroup( Index ) --- end -function SPAWN:GetNextAliveGroup( SpawnIndexStart ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndexStart } ) - - SpawnIndexStart = SpawnIndexStart + 1 - for SpawnIndex = SpawnIndexStart, self.SpawnCount do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - return SpawnGroup, SpawnIndex - end - end - - return nil, nil -end - ---- Will find the last alive @{Group} object, and will return a reference to the last live @{Group} object and the last Index where the last alive @{Group} object has been found. --- @param #SPAWN self --- @return Wrapper.Group#GROUP, #number The last alive @{Group} object found, the last Index where the last alive @{Group} object was found. --- @return #nil, #nil When no alive @{Group} object is found, #nil is returned. --- @usage --- -- Find the last alive @{Group} object of the SpawnPlanes SPAWN object @{Group} collection that it has spawned during the mission. --- local GroupPlane, Index = SpawnPlanes:GetLastAliveGroup() --- if GroupPlane then -- GroupPlane can be nil!!! --- -- Do actions with the GroupPlane object. --- end -function SPAWN:GetLastAliveGroup() - self:F( { self.SpawnTemplatePrefixself.SpawnAliasPrefix } ) - - self.SpawnIndex = self:_GetLastIndex() - for SpawnIndex = self.SpawnIndex, 1, -1 do - local SpawnGroup = self:GetGroupFromIndex( SpawnIndex ) - if SpawnGroup and SpawnGroup:IsAlive() then - self.SpawnIndex = SpawnIndex - return SpawnGroup - end - end - - self.SpawnIndex = nil - return nil -end - - - ---- Get the group from an index. --- Returns the group from the SpawnGroups list. --- If no index is given, it will return the first group in the list. --- @param #SPAWN self --- @param #number SpawnIndex The index of the group to return. --- @return Wrapper.Group#GROUP self -function SPAWN:GetGroupFromIndex( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) - - if not SpawnIndex then - SpawnIndex = 1 - end - - if self.SpawnGroups and self.SpawnGroups[SpawnIndex] then - local SpawnGroup = self.SpawnGroups[SpawnIndex].Group - return SpawnGroup - else - return nil - end -end - ---- Get the group index from a DCSUnit. --- The method will search for a #-mark, and will return the index behind the #-mark of the DCSUnit. --- It will return nil of no prefix was found. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit The @{DCSUnit} to be searched. --- @return #string The prefix --- @return #nil Nothing found -function SPAWN:_GetGroupIndexFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local SpawnUnitName = ( DCSUnit and DCSUnit:getName() ) or nil - if SpawnUnitName then - local IndexString = string.match( SpawnUnitName, "#.*-" ):sub( 2, -2 ) - if IndexString then - local Index = tonumber( IndexString ) - return Index - end - end - - return nil -end - ---- Return the prefix of a SpawnUnit. --- The method will search for a #-mark, and will return the text before the #-mark. --- It will return nil of no prefix was found. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#UNIT DCSUnit The @{DCSUnit} to be searched. --- @return #string The prefix --- @return #nil Nothing found -function SPAWN:_GetPrefixFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local DCSUnitName = ( DCSUnit and DCSUnit:getName() ) or nil - if DCSUnitName then - local SpawnPrefix = string.match( DCSUnitName, ".*#" ) - if SpawnPrefix then - SpawnPrefix = SpawnPrefix:sub( 1, -2 ) - end - return SpawnPrefix - end - - return nil -end - ---- Return the group within the SpawnGroups collection with input a DCSUnit. --- @param #SPAWN self --- @param Dcs.DCSWrapper.Unit#Unit DCSUnit The @{DCSUnit} to be searched. --- @return Wrapper.Group#GROUP The Group --- @return #nil Nothing found -function SPAWN:_GetGroupFromDCSUnit( DCSUnit ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, DCSUnit } ) - - local SpawnPrefix = self:_GetPrefixFromDCSUnit( DCSUnit ) - - if self.SpawnTemplatePrefix == SpawnPrefix or ( self.SpawnAliasPrefix and self.SpawnAliasPrefix == SpawnPrefix ) then - local SpawnGroupIndex = self:_GetGroupIndexFromDCSUnit( DCSUnit ) - local SpawnGroup = self.SpawnGroups[SpawnGroupIndex].Group - self:T( SpawnGroup ) - return SpawnGroup - end - - return nil -end - - ---- Get the index from a given group. --- The function will search the name of the group for a #, and will return the number behind the #-mark. -function SPAWN:GetSpawnIndexFromGroup( SpawnGroup ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } ) - - local IndexString = string.match( SpawnGroup:GetName(), "#.*$" ):sub( 2 ) - local Index = tonumber( IndexString ) - - self:T3( IndexString, Index ) - return Index - -end - ---- Return the last maximum index that can be used. -function SPAWN:_GetLastIndex() - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - return self.SpawnMaxGroups -end - ---- Initalize the SpawnGroups collection. -function SPAWN:_InitializeSpawnGroups( SpawnIndex ) - self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnIndex } ) - - if not self.SpawnGroups[SpawnIndex] then - self.SpawnGroups[SpawnIndex] = {} - self.SpawnGroups[SpawnIndex].Visible = false - self.SpawnGroups[SpawnIndex].Spawned = false - self.SpawnGroups[SpawnIndex].UnControlled = false - self.SpawnGroups[SpawnIndex].SpawnTime = 0 - - self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefix - self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) - end - - self:_RandomizeTemplate( SpawnIndex ) - self:_RandomizeRoute( SpawnIndex ) - --self:_TranslateRotate( SpawnIndex ) - - return self.SpawnGroups[SpawnIndex] -end - - - ---- Gets the CategoryID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCategoryID( SpawnPrefix ) - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - return TemplateGroup:getCategory() - else - return nil - end -end - ---- Gets the CoalitionID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCoalitionID( SpawnPrefix ) - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - return TemplateGroup:getCoalition() - else - return nil - end -end - ---- Gets the CountryID of the Group with the given SpawnPrefix -function SPAWN:_GetGroupCountryID( SpawnPrefix ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnPrefix } ) - - local TemplateGroup = Group.getByName( SpawnPrefix ) - - if TemplateGroup then - local TemplateUnits = TemplateGroup:getUnits() - return TemplateUnits[1]:getCountry() - else - return nil - end -end - ---- Gets the Group Template from the ME environment definition. --- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix --- @return @SPAWN self -function SPAWN:_GetTemplate( SpawnTemplatePrefix ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } ) - - local SpawnTemplate = nil - - SpawnTemplate = routines.utils.deepCopy( _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template ) - - if SpawnTemplate == nil then - error( 'No Template returned for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix ) - end - - --SpawnTemplate.SpawnCoalitionID = self:_GetGroupCoalitionID( SpawnTemplatePrefix ) - --SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnTemplatePrefix ) - --SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnTemplatePrefix ) - - self:T3( { SpawnTemplate } ) - return SpawnTemplate -end - ---- Prepares the new Group Template. --- @param #SPAWN self --- @param #string SpawnTemplatePrefix --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) - - local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) - SpawnTemplate.name = self:SpawnGroupName( SpawnIndex ) - - SpawnTemplate.groupId = nil - --SpawnTemplate.lateActivation = false - SpawnTemplate.lateActivation = false - - if SpawnTemplate.CategoryID == Group.Category.GROUND then - self:T3( "For ground units, visible needs to be false..." ) - SpawnTemplate.visible = false - end - - if SpawnTemplate.CategoryID == Group.Category.HELICOPTER or SpawnTemplate.CategoryID == Group.Category.AIRPLANE then - SpawnTemplate.uncontrolled = false - end - - for UnitID = 1, #SpawnTemplate.units do - SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID ) - SpawnTemplate.units[UnitID].unitId = nil - end - - self:T3( { "Template:", SpawnTemplate } ) - return SpawnTemplate - -end - ---- Private method randomizing the routes. --- @param #SPAWN self --- @param #number SpawnIndex The index of the group to be spawned. --- @return #SPAWN -function SPAWN:_RandomizeRoute( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeRoute, self.SpawnRandomizeRouteStartPoint, self.SpawnRandomizeRouteEndPoint, self.SpawnRandomizeRouteRadius } ) - - if self.SpawnRandomizeRoute then - local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate - local RouteCount = #SpawnTemplate.route.points - - for t = self.SpawnRandomizeRouteStartPoint + 1, ( RouteCount - self.SpawnRandomizeRouteEndPoint ) do - - SpawnTemplate.route.points[t].x = SpawnTemplate.route.points[t].x + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) - SpawnTemplate.route.points[t].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRandomizeRouteRadius * -1, self.SpawnRandomizeRouteRadius ) - - -- Manage randomization of altitude for airborne units ... - if SpawnTemplate.CategoryID == Group.Category.AIRPLANE or SpawnTemplate.CategoryID == Group.Category.HELICOPTER then - if SpawnTemplate.route.points[t].alt and self.SpawnRandomizeRouteHeight then - SpawnTemplate.route.points[t].alt = SpawnTemplate.route.points[t].alt + math.random( 1, self.SpawnRandomizeRouteHeight ) - end - else - SpawnTemplate.route.points[t].alt = nil - end - - self:T( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y ) - end - end - - self:_RandomizeZones( SpawnIndex ) - - return self -end - ---- Private method that randomizes the template of the group. --- @param #SPAWN self --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_RandomizeTemplate( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeTemplate } ) - - if self.SpawnRandomizeTemplate then - self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix = self.SpawnTemplatePrefixTable[ math.random( 1, #self.SpawnTemplatePrefixTable ) ] - self.SpawnGroups[SpawnIndex].SpawnTemplate = self:_Prepare( self.SpawnGroups[SpawnIndex].SpawnTemplatePrefix, SpawnIndex ) - self.SpawnGroups[SpawnIndex].SpawnTemplate.route = routines.utils.deepCopy( self.SpawnTemplate.route ) - self.SpawnGroups[SpawnIndex].SpawnTemplate.x = self.SpawnTemplate.x - self.SpawnGroups[SpawnIndex].SpawnTemplate.y = self.SpawnTemplate.y - self.SpawnGroups[SpawnIndex].SpawnTemplate.start_time = self.SpawnTemplate.start_time - for UnitID = 1, #self.SpawnGroups[SpawnIndex].SpawnTemplate.units do - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].heading = self.SpawnTemplate.units[1].heading - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].x = self.SpawnTemplate.units[1].x - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].y = self.SpawnTemplate.units[1].y - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[UnitID].alt = self.SpawnTemplate.units[1].alt - end - end - - self:_RandomizeRoute( SpawnIndex ) - - return self -end - ---- Private method that randomizes the @{Zone}s where the Group will be spawned. --- @param #SPAWN self --- @param #number SpawnIndex --- @return #SPAWN self -function SPAWN:_RandomizeZones( SpawnIndex ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } ) - - if self.SpawnRandomizeZones then - local SpawnZone = nil -- Core.Zone#ZONE_BASE - while not SpawnZone do - self:T( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } ) - local ZoneID = math.random( #self.SpawnZoneTable ) - self:T( ZoneID ) - SpawnZone = self.SpawnZoneTable[ ZoneID ]:GetZoneMaybe() - end - - self:T( "Preparing Spawn in Zone", SpawnZone:GetName() ) - - local SpawnVec2 = SpawnZone:GetRandomVec2() - - self:T( { SpawnVec2 = SpawnVec2 } ) - - local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate - - self:T( { Route = SpawnTemplate.route } ) - - for UnitID = 1, #SpawnTemplate.units do - local UnitTemplate = SpawnTemplate.units[UnitID] - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = SpawnTemplate.route.points[1].x - local BY = SpawnTemplate.route.points[1].y - local TX = SpawnVec2.x + ( SX - BX ) - local TY = SpawnVec2.y + ( SY - BY ) - UnitTemplate.x = TX - UnitTemplate.y = TY - -- TODO: Manage altitude based on landheight... - --SpawnTemplate.units[UnitID].alt = SpawnVec2: - self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) - end - SpawnTemplate.x = SpawnVec2.x - SpawnTemplate.y = SpawnVec2.y - SpawnTemplate.route.points[1].x = SpawnVec2.x - SpawnTemplate.route.points[1].y = SpawnVec2.y - end - - return self - -end - -function SPAWN:_TranslateRotate( SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle ) - self:F( { self.SpawnTemplatePrefix, SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle } ) - - -- Translate - local TranslatedX = SpawnX - local TranslatedY = SpawnY - - -- Rotate - -- From Wikipedia: https://en.wikipedia.org/wiki/Rotation_matrix#Common_rotations - -- x' = x \cos \theta - y \sin \theta\ - -- y' = x \sin \theta + y \cos \theta\ - local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) - + TranslatedY * math.sin( math.rad( SpawnAngle ) ) - local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) - + TranslatedY * math.cos( math.rad( SpawnAngle ) ) - - -- Assign - self.SpawnGroups[SpawnIndex].SpawnTemplate.x = SpawnRootX - RotatedX - self.SpawnGroups[SpawnIndex].SpawnTemplate.y = SpawnRootY + RotatedY - - - local SpawnUnitCount = table.getn( self.SpawnGroups[SpawnIndex].SpawnTemplate.units ) - for u = 1, SpawnUnitCount do - - -- Translate - local TranslatedX = SpawnX - local TranslatedY = SpawnY - 10 * ( u - 1 ) - - -- Rotate - local RotatedX = - TranslatedX * math.cos( math.rad( SpawnAngle ) ) - + TranslatedY * math.sin( math.rad( SpawnAngle ) ) - local RotatedY = TranslatedX * math.sin( math.rad( SpawnAngle ) ) - + TranslatedY * math.cos( math.rad( SpawnAngle ) ) - - -- Assign - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].x = SpawnRootX - RotatedX - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].y = SpawnRootY + RotatedY - self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading = self.SpawnGroups[SpawnIndex].SpawnTemplate.units[u].heading + math.rad( SpawnAngle ) - end - - return self -end - ---- Get the next index of the groups to be spawned. This method is complicated, as it is used at several spaces. -function SPAWN:_GetSpawnIndex( SpawnIndex ) - self:F2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive, self.AliveUnits, #self.SpawnTemplate.units } ) - - if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then - if ( self.SpawnMaxUnitsAlive == 0 ) or ( self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive ) or self.UnControlled == true then - if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then - self.SpawnCount = self.SpawnCount + 1 - SpawnIndex = self.SpawnCount - end - self.SpawnIndex = SpawnIndex - if not self.SpawnGroups[self.SpawnIndex] then - self:_InitializeSpawnGroups( self.SpawnIndex ) - end - else - return nil - end - else - return nil - end - - return self.SpawnIndex -end - - --- TODO Need to delete this... _DATABASE does this now ... - ---- @param #SPAWN self --- @param Core.Event#EVENTDATA Event -function SPAWN:_OnBirth( Event ) - - if timer.getTime0() < timer.getAbsTime() then - if Event.IniDCSUnit then - local EventPrefix = self:_GetPrefixFromDCSUnit( Event.IniDCSUnit ) - self:T( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits + 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end - end - end - -end - ---- Obscolete --- @todo Need to delete this... _DATABASE does this now ... - ---- @param #SPAWN self --- @param Core.Event#EVENTDATA Event -function SPAWN:_OnDeadOrCrash( Event ) - self:F( self.SpawnTemplatePrefix, Event ) - - if Event.IniDCSUnit then - local EventPrefix = self:_GetPrefixFromDCSUnit( Event.IniDCSUnit ) - self:T( { "Dead event: " .. EventPrefix, self.SpawnTemplatePrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits - 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end - end -end - ---- Will detect AIR Units taking off... When the event takes place, the spawned Group is registered as airborne... --- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups. --- @todo Need to test for AIR Groups only... -function SPAWN:_OnTakeOff( event ) - self:F( self.SpawnTemplatePrefix, event ) - - if event.initiator and event.initiator:getName() then - local SpawnGroup = self:_GetGroupFromDCSUnit( event.initiator ) - if SpawnGroup then - self:T( { "TakeOff event: " .. event.initiator:getName(), event } ) - self:T( "self.Landed = false" ) - self.Landed = false - end - end -end - ---- Will detect AIR Units landing... When the event takes place, the spawned Group is registered as landed. --- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups. --- @todo Need to test for AIR Groups only... -function SPAWN:_OnLand( event ) - self:F( self.SpawnTemplatePrefix, event ) - - local SpawnUnit = event.initiator - if SpawnUnit and SpawnUnit:isExist() and Object.getCategory(SpawnUnit) == Object.Category.UNIT then - local SpawnGroup = self:_GetGroupFromDCSUnit( SpawnUnit ) - if SpawnGroup then - self:T( { "Landed event:" .. SpawnUnit:getName(), event } ) - self.Landed = true - self:T( "self.Landed = true" ) - if self.Landed and self.RepeatOnLanding then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end - end -end - ---- Will detect AIR Units shutting down their engines ... --- When the event takes place, and the method @{RepeatOnEngineShutDown} was called, the spawned Group will Re-SPAWN. --- But only when the Unit was registered to have landed. --- @param #SPAWN self --- @see _OnTakeOff --- @see _OnLand --- @todo Need to test for AIR Groups only... -function SPAWN:_OnEngineShutDown( event ) - self:F( self.SpawnTemplatePrefix, event ) - - local SpawnUnit = event.initiator - if SpawnUnit and SpawnUnit:isExist() and Object.getCategory(SpawnUnit) == Object.Category.UNIT then - local SpawnGroup = self:_GetGroupFromDCSUnit( SpawnUnit ) - if SpawnGroup then - self:T( { "EngineShutDown event: " .. SpawnUnit:getName(), event } ) - if self.Landed and self.RepeatOnEngineShutDown then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end - end -end - ---- This function is called automatically by the Spawning scheduler. --- It is the internal worker method SPAWNing new Groups on the defined time intervals. -function SPAWN:_Scheduler() - self:F2( { "_Scheduler", self.SpawnTemplatePrefix, self.SpawnAliasPrefix, self.SpawnIndex, self.SpawnMaxGroups, self.SpawnMaxUnitsAlive } ) - - -- Validate if there are still groups left in the batch... - self:Spawn() - - return true -end - ---- Schedules the CleanUp of Groups --- @param #SPAWN self --- @return #boolean True = Continue Scheduler -function SPAWN:_SpawnCleanUpScheduler() - self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) - - local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() - self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) - - while SpawnGroup do - - local SpawnUnits = SpawnGroup:GetUnits() - - for UnitID, UnitData in pairs( SpawnUnits ) do - - local SpawnUnit = UnitData -- Wrapper.Unit#UNIT - local SpawnUnitName = SpawnUnit:GetName() - - - self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {} - local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] - self:T( { SpawnUnitName, Stamp } ) - - if Stamp.Vec2 then - if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then - local NewVec2 = SpawnUnit:GetVec2() - if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then - -- If the plane is not moving, and is on the ground, assign it with a timestamp... - if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Vec2 = nil - Stamp.Time = nil - end - else - Stamp.Time = timer.getTime() - Stamp.Vec2 = SpawnUnit:GetVec2() - end - else - Stamp.Vec2 = nil - Stamp.Time = nil - end - else - if SpawnUnit:InAir() == false then - Stamp.Vec2 = SpawnUnit:GetVec2() - if SpawnUnit:GetVelocityKMH() < 1 then - Stamp.Time = timer.getTime() - end - else - Stamp.Time = nil - Stamp.Vec2 = nil - end - end - end - - SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor ) - - self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) - - end - - return true -- Repeat - -end ---- Limit the simultaneous movement of Groups within a running Mission. --- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles. --- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if --- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units --- on defined intervals (currently every minute). --- @module MOVEMENT - ---- the MOVEMENT class --- @type -MOVEMENT = { - ClassName = "MOVEMENT", -} - ---- Creates the main object which is handling the GROUND forces movement. --- @param table{string,...}|string MovePrefixes is a table of the Prefixes (names) of the GROUND Groups that need to be controlled by the MOVEMENT Object. --- @param number MoveMaximum is a number that defines the maximum amount of GROUND Units to be moving during one minute. --- @return MOVEMENT --- @usage --- -- Limit the amount of simultaneous moving units on the ground to prevent lag. --- Movement_US_Platoons = MOVEMENT:New( { 'US Tank Platoon Left', 'US Tank Platoon Middle', 'US Tank Platoon Right', 'US CH-47D Troops' }, 15 ) - -function MOVEMENT:New( MovePrefixes, MoveMaximum ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { MovePrefixes, MoveMaximum } ) - - if type( MovePrefixes ) == 'table' then - self.MovePrefixes = MovePrefixes - else - self.MovePrefixes = { MovePrefixes } - end - self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart. - self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move... - self.AliveUnits = 0 -- Contains the counter how many units are currently alive - self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not. - - _EVENTDISPATCHER:OnBirth( self.OnBirth, self ) - --- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth ) --- --- self:EnableEvents() - - self:ScheduleStart() - - return self -end - ---- Call this function to start the MOVEMENT scheduling. -function MOVEMENT:ScheduleStart() - self:F() - --self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) - self.MoveFunction = SCHEDULER:New( self, self._Scheduler, {}, 1, 120 ) -end - ---- Call this function to stop the MOVEMENT scheduling. --- @todo need to implement it ... Forgot. -function MOVEMENT:ScheduleStop() - self:F() - -end - ---- Captures the birth events when new Units were spawned. --- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. -function MOVEMENT:OnBirth( Event ) - self:F( { Event } ) - - if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line - if Event.IniDCSUnit then - self:T( "Birth object : " .. Event.IniDCSUnitName ) - if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then - for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do - if string.find( Event.IniDCSUnitName, MovePrefix, 1, true ) then - self.AliveUnits = self.AliveUnits + 1 - self.MoveUnits[Event.IniDCSUnitName] = Event.IniDCSGroupName - self:T( self.AliveUnits ) - end - end - end - end - _EVENTDISPATCHER:OnCrashForUnit( Event.IniDCSUnitName, self.OnDeadOrCrash, self ) - _EVENTDISPATCHER:OnDeadForUnit( Event.IniDCSUnitName, self.OnDeadOrCrash, self ) - end - -end - ---- Captures the Dead or Crash events when Units crash or are destroyed. --- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. -function MOVEMENT:OnDeadOrCrash( Event ) - self:F( { Event } ) - - if Event.IniDCSUnit then - self:T( "Dead object : " .. Event.IniDCSUnitName ) - for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do - if string.find( Event.IniDCSUnitName, MovePrefix, 1, true ) then - self.AliveUnits = self.AliveUnits - 1 - self.MoveUnits[Event.IniDCSUnitName] = nil - self:T( self.AliveUnits ) - end - end - end -end - ---- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true. -function MOVEMENT:_Scheduler() - self:F( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } ) - - if self.AliveUnits > 0 then - local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits - self:T( 'Move Probability = ' .. MoveProbability ) - - for MovementUnitName, MovementGroupName in pairs( self.MoveUnits ) do - local MovementGroup = Group.getByName( MovementGroupName ) - if MovementGroup and MovementGroup:isExist() then - local MoveOrStop = math.random( 1, 100 ) - self:T( 'MoveOrStop = ' .. MoveOrStop ) - if MoveOrStop <= MoveProbability then - self:T( 'Group continues moving = ' .. MovementGroupName ) - trigger.action.groupContinueMoving( MovementGroup ) - else - self:T( 'Group stops moving = ' .. MovementGroupName ) - trigger.action.groupStopMoving( MovementGroup ) - end - else - self.MoveUnits[MovementUnitName] = nil - end - end - end - return true -end ---- Provides defensive behaviour to a set of SAM sites within a running Mission. --- @module Sead --- @author to be searched on the forum --- @author (co) Flightcontrol (Modified and enriched with functionality) - ---- The SEAD class --- @type SEAD --- @extends Core.Base#BASE -SEAD = { - ClassName = "SEAD", - TargetSkill = { - Average = { Evade = 50, DelayOff = { 10, 25 }, DelayOn = { 10, 30 } } , - Good = { Evade = 30, DelayOff = { 8, 20 }, DelayOn = { 20, 40 } } , - High = { Evade = 15, DelayOff = { 5, 17 }, DelayOn = { 30, 50 } } , - Excellent = { Evade = 10, DelayOff = { 3, 10 }, DelayOn = { 30, 60 } } - }, - SEADGroupPrefixes = {} -} - ---- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. --- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions... --- Chances are big that the missile will miss. --- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCSRTE on which evasive actions need to be taken. --- @return SEAD --- @usage --- -- CCCP SEAD Defenses --- -- Defends the Russian SA installations from SEAD attacks. --- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) -function SEAD:New( SEADGroupPrefixes ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( SEADGroupPrefixes ) - if type( SEADGroupPrefixes ) == 'table' then - for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do - self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix - end - else - self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes - end - _EVENTDISPATCHER:OnShot( self.EventShot, self ) - - return self -end - ---- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. --- @see SEAD -function SEAD:EventShot( Event ) - self:F( { Event } ) - - local SEADUnit = Event.IniDCSUnit - local SEADUnitName = Event.IniDCSUnitName - local SEADWeapon = Event.Weapon -- Identify the weapon fired - local SEADWeaponName = Event.WeaponName -- return weapon type - -- Start of the 2nd loop - self:T( "Missile Launched = " .. SEADWeaponName ) - if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD - local _evade = math.random (1,100) -- random number for chance of evading action - local _targetMim = Event.Weapon:getTarget() -- Identify target - local _targetMimname = Unit.getName(_targetMim) - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimgroupName = _targetMimgroup:getName() - local _targetMimcont= _targetMimgroup:getController() - local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill - self:T( self.SEADGroupPrefixes ) - self:T( _targetMimgroupName ) - local SEADGroupFound = false - for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do - if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then - SEADGroupFound = true - self:T( 'Group Found' ) - break - end - end - if SEADGroupFound == true then - if _targetskill == "Random" then -- when skill is random, choose a skill - local Skills = { "Average", "Good", "High", "Excellent" } - _targetskill = Skills[ math.random(1,4) ] - end - self:T( _targetskill ) - if self.TargetSkill[_targetskill] then - if (_evade > self.TargetSkill[_targetskill].Evade) then - self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) - local _targetMim = Weapon.getTarget(SEADWeapon) - local _targetMimname = Unit.getName(_targetMim) - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimcont= _targetMimgroup:getController() - routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly - local SuppressedGroups1 = {} -- unit suppressed radar off for a random time - local function SuppressionEnd1(id) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - SuppressedGroups1[id.groupName] = nil - end - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2]) - if SuppressedGroups1[id.groupName] == nil then - SuppressedGroups1[id.groupName] = { - SuppressionEndTime1 = timer.getTime() + delay1, - SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function - } - Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20) - end - - local SuppressedGroups = {} - local function SuppressionEnd(id) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) - SuppressedGroups[id.groupName] = nil - end - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) - if SuppressedGroups[id.groupName] == nil then - SuppressedGroups[id.groupName] = { - SuppressionEndTime = timer.getTime() + delay, - SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function - } - timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function - --trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20) - end - end - end - end - end -end ---- Taking the lead of AI escorting your flight. --- --- @{#ESCORT} class --- ================ --- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead. --- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10). --- --- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes. --- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts. --- --- RADIO MENUs that can be created: --- ================================ --- Find a summary below of the current available commands: --- --- Navigation ...: --- --------------- --- Escort group navigation functions: --- --- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you. --- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color. --- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops. --- --- Hold position ...: --- ------------------ --- Escort group navigation functions: --- --- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped. --- --- Report targets ...: --- ------------------- --- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below). --- --- * **"Report now":** Will report the current detected targets. --- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list. --- * **"Report targets off":** Will stop detecting targets. --- --- Scan targets ...: --- ----------------- --- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task. --- --- * **"Scan targets 30 seconds":** Scan 30 seconds for targets. --- * **"Scan targets 60 seconds":** Scan 60 seconds for targets. --- --- Attack targets ...: --- ------------------- --- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed. --- --- Request assistance from ...: --- ---------------------------- --- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**. --- This menu item allows to request attack support from other escorts supporting the current client group. --- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles. --- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area. --- --- ROE ...: --- -------- --- Sets the Rules of Engagement (ROE) of the escort group when in flight. --- --- * **"Hold Fire":** The escort group will hold fire. --- * **"Return Fire":** The escort group will return fire. --- * **"Open Fire":** The escort group will open fire on designated targets. --- * **"Weapon Free":** The escort group will engage with any target. --- --- Evasion ...: --- ------------ --- Will define the evasion techniques that the escort group will perform during flight or combat. --- --- * **"Fight until death":** The escort group will have no reaction to threats. --- * **"Use flares, chaff and jammers":** The escort group will use passive defense using flares and jammers. No evasive manoeuvres are executed. --- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing. --- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres. --- --- Resume Mission ...: --- ------------------- --- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint. --- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission. --- --- ESCORT construction methods. --- ============================ --- Create a new SPAWN object with the @{#ESCORT.New} method: --- --- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text. --- --- ESCORT initialization methods. --- ============================== --- The following menus are created within the RADIO MENU of an active unit hosted by a player: --- --- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client. --- * @{#ESCORT.MenuHoldAtEscortPosition}: Creates a menu to hold the escort at its current position. --- * @{#ESCORT.MenuHoldAtLeaderPosition}: Creates a menu to hold the escort at the client position. --- * @{#ESCORT.MenuScanForTargets}: Creates a menu so that the escort scans targets. --- * @{#ESCORT.MenuFlare}: Creates a menu to disperse flares. --- * @{#ESCORT.MenuSmoke}: Creates a menu to disparse smoke. --- * @{#ESCORT.MenuReportTargets}: Creates a menu so that the escort reports targets. --- * @{#ESCORT.MenuReportPosition}: Creates a menu so that the escort reports its current position from bullseye. --- * @{#ESCORT.MenuAssistedAttack: Creates a menu so that the escort supportes assisted attack from other escorts with the client. --- * @{#ESCORT.MenuROE: Creates a menu structure to set the rules of engagement of the escort. --- * @{#ESCORT.MenuEvasion: Creates a menu structure to set the evasion techniques when the escort is under threat. --- * @{#ESCORT.MenuResumeMission}: Creates a menu structure so that the escort can resume from a waypoint. --- --- --- @usage --- -- Declare a new EscortPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. --- --- -- Now use these 2 objects to construct the new EscortPlanes object. --- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) --- --- --- --- @module Escort --- @author FlightControl - ---- ESCORT class --- @type ESCORT --- @extends Core.Base#BASE --- @field Wrapper.Client#CLIENT EscortClient --- @field Wrapper.Group#GROUP EscortGroup --- @field #string EscortName --- @field #ESCORT.MODE EscortMode The mode the escort is in. --- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. --- @field #number FollowDistance The current follow distance. --- @field #boolean ReportTargets If true, nearby targets are reported. --- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup. --- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup. --- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission -ESCORT = { - ClassName = "ESCORT", - EscortName = nil, -- The Escort Name - EscortClient = nil, - EscortGroup = nil, - EscortMode = 1, - MODE = { - FOLLOW = 1, - MISSION = 2, - }, - Targets = {}, -- The identified targets - FollowScheduler = nil, - ReportTargets = true, - OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, - OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, - SmokeDirectionVector = false, - TaskPoints = {} -} - ---- ESCORT.Mode class --- @type ESCORT.MODE --- @field #number FOLLOW --- @field #number MISSION - ---- MENUPARAM type --- @type MENUPARAM --- @field #ESCORT ParamSelf --- @field #Distance ParamDistance --- @field #function ParamFunction --- @field #string ParamMessage - ---- ESCORT class constructor for an AI group --- @param #ESCORT self --- @param Wrapper.Client#CLIENT EscortClient The client escorted by the EscortGroup. --- @param Wrapper.Group#GROUP EscortGroup The group AI escorting the EscortClient. --- @param #string EscortName Name of the escort. --- @param #string EscortBriefing A text showing the ESCORT briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown. --- @return #ESCORT self --- @usage --- -- Declare a new EscortPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local EscortClient = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. --- --- -- Now use these 2 objects to construct the new EscortPlanes object. --- EscortPlanes = ESCORT:New( EscortClient, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) -function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( { EscortClient, EscortGroup, EscortName } ) - - self.EscortClient = EscortClient -- Wrapper.Client#CLIENT - self.EscortGroup = EscortGroup -- Wrapper.Group#GROUP - self.EscortName = EscortName - self.EscortBriefing = EscortBriefing - - -- Set EscortGroup known at EscortClient. - if not self.EscortClient._EscortGroups then - self.EscortClient._EscortGroups = {} - end - - if not self.EscortClient._EscortGroups[EscortGroup:GetName()] then - self.EscortClient._EscortGroups[EscortGroup:GetName()] = {} - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortGroup = self.EscortGroup - self.EscortClient._EscortGroups[EscortGroup:GetName()].EscortName = self.EscortName - self.EscortClient._EscortGroups[EscortGroup:GetName()].Targets = {} - end - - self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName ) - - self.EscortGroup:WayPointInitialize(1) - - self.EscortGroup:OptionROTVertical() - self.EscortGroup:OptionROEOpenFire() - - if not EscortBriefing then - EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. - "We're escorting your flight. " .. - "Use the Radio Menu and F10 and use the options under + " .. EscortName .. "\n", - 60, EscortClient - ) - else - EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") " .. EscortBriefing, - 60, EscortClient - ) - end - - self.FollowDistance = 100 - self.CT1 = 0 - self.GT1 = 0 - self.FollowScheduler = SCHEDULER:New( self, self._FollowScheduler, {}, 1, .5, .01 ) - self.EscortMode = ESCORT.MODE.MISSION - self.FollowScheduler:Stop() - - return self -end - ---- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to. --- This allows to visualize where the escort is flying to. --- @param #ESCORT self --- @param #boolean SmokeDirection If true, then the direction vector will be smoked. -function ESCORT:TestSmokeDirectionVector( SmokeDirection ) - self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false -end - - ---- Defines the default menus --- @param #ESCORT self --- @return #ESCORT -function ESCORT:Menus() - self:F() - - self:MenuFollowAt( 100 ) - self:MenuFollowAt( 200 ) - self:MenuFollowAt( 300 ) - self:MenuFollowAt( 400 ) - - self:MenuScanForTargets( 100, 60 ) - - self:MenuHoldAtEscortPosition( 30 ) - self:MenuHoldAtLeaderPosition( 30 ) - - self:MenuFlare() - self:MenuSmoke() - - self:MenuReportTargets( 60 ) - self:MenuAssistedAttack() - self:MenuROE() - self:MenuEvasion() - self:MenuResumeMission() - - - return self -end - - - ---- Defines a menu slot to let the escort Join and Follow you at a certain distance. --- This menu will appear under **Navigation**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client. --- @return #ESCORT -function ESCORT:MenuFollowAt( Distance ) - self:F(Distance) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - if not self.EscortMenuJoinUpAndFollow then - self.EscortMenuJoinUpAndFollow = {} - end - - self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, { ParamSelf = self, ParamDistance = Distance } ) - - self.EscortMode = ESCORT.MODE.FOLLOW - end - - return self -end - ---- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds. --- This menu will appear under **Hold position**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT --- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. -function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - - if not self.EscortMenuHold then - self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) - end - - if not Height then - Height = 30 - end - - if not Seconds then - Seconds = 0 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "Hold at %d meter", Height ) - else - MenuText = string.format( "Hold at %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuHoldPosition then - self.EscortMenuHoldPosition = {} - end - - self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuHold, - ESCORT._HoldPosition, - { ParamSelf = self, - ParamOrbitGroup = self.EscortGroup, - ParamHeight = Height, - ParamSeconds = Seconds - } - ) - end - - return self -end - - ---- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds. --- This menu will appear under **Navigation**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT --- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function. -function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - - if not self.EscortMenuHold then - self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu ) - end - - if not Height then - Height = 30 - end - - if not Seconds then - Seconds = 0 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "Rejoin and hold at %d meter", Height ) - else - MenuText = string.format( "Rejoin and hold at %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuHoldAtLeaderPosition then - self.EscortMenuHoldAtLeaderPosition = {} - end - - self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuHold, - ESCORT._HoldPosition, - { ParamSelf = self, - ParamOrbitGroup = self.EscortClient, - ParamHeight = Height, - ParamSeconds = Seconds - } - ) - end - - return self -end - ---- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds. --- This menu will appear under **Scan targets**. --- @param #ESCORT self --- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters. --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given. --- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat ) - self:F( { Height, Seconds, MenuTextFormat } ) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuScan then - self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu ) - end - - if not Height then - Height = 100 - end - - if not Seconds then - Seconds = 30 - end - - local MenuText = "" - if not MenuTextFormat then - if Seconds == 0 then - MenuText = string.format( "At %d meter", Height ) - else - MenuText = string.format( "At %d meter for %d seconds", Height, Seconds ) - end - else - if Seconds == 0 then - MenuText = string.format( MenuTextFormat, Height ) - else - MenuText = string.format( MenuTextFormat, Height, Seconds ) - end - end - - if not self.EscortMenuScanForTargets then - self.EscortMenuScanForTargets = {} - end - - self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND - :New( - self.EscortClient, - MenuText, - self.EscortMenuScan, - ESCORT._ScanTargets, - { ParamSelf = self, - ParamScanDuration = 30 - } - ) - end - - return self -end - - - ---- Defines a menu slot to let the escort disperse a flare in a certain color. --- This menu will appear under **Navigation**. --- The flare will be fired from the first unit in the group. --- @param #ESCORT self --- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuFlare( MenuTextFormat ) - self:F() - - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Flare" - else - MenuText = MenuTextFormat - end - - if not self.EscortMenuFlare then - self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, { ParamSelf = self } ) - self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Green, ParamMessage = "Released a green flare!" } ) - self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Red, ParamMessage = "Released a red flare!" } ) - self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.White, ParamMessage = "Released a white flare!" } ) - self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Yellow, ParamMessage = "Released a yellow flare!" } ) - end - - return self -end - ---- Defines a menu slot to let the escort disperse a smoke in a certain color. --- This menu will appear under **Navigation**. --- Note that smoke menu options will only be displayed for ships and ground units. Not for air units. --- The smoke will be fired from the first unit in the group. --- @param #ESCORT self --- @param #string MenuTextFormat Optional parameter that shows the menu option text. If no text is given, the default text will be displayed. --- @return #ESCORT -function ESCORT:MenuSmoke( MenuTextFormat ) - self:F() - - if not self.EscortGroup:IsAir() then - if not self.EscortMenuReportNavigation then - self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu ) - end - - local MenuText = "" - if not MenuTextFormat then - MenuText = "Smoke" - else - MenuText = MenuTextFormat - end - - if not self.EscortMenuSmoke then - self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, { ParamSelf = self } ) - self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Green, ParamMessage = "Releasing green smoke!" } ) - self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Red, ParamMessage = "Releasing red smoke!" } ) - self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.White, ParamMessage = "Releasing white smoke!" } ) - self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Orange, ParamMessage = "Releasing orange smoke!" } ) - self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, { ParamSelf = self, ParamColor = UNIT.SmokeColor.Blue, ParamMessage = "Releasing blue smoke!" } ) - end - end - - return self -end - ---- Defines a menu slot to let the escort report their current detected targets with a specified time interval in seconds. --- This menu will appear under **Report targets**. --- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed. --- @param #ESCORT self --- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds. --- @return #ESCORT -function ESCORT:MenuReportTargets( Seconds ) - self:F( { Seconds } ) - - if not self.EscortMenuReportNearbyTargets then - self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu ) - end - - if not Seconds then - Seconds = 30 - end - - -- Report Targets - self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, { ParamSelf = self } ) - self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = true } ) - self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, { ParamSelf = self, ParamReportTargets = false, } ) - - -- Attack Targets - self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - - - self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) - - return self -end - ---- Defines a menu slot to let the escort attack its detected targets using assisted attack from another escort joined also with the client. --- This menu will appear under **Request assistance from**. --- Note that this method needs to be preceded with the method MenuReportTargets. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuAssistedAttack() - self:F() - - -- Request assistance from other escorts. - -- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane... - self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu ) - - return self -end - ---- Defines a menu to let the escort set its rules of engagement. --- All rules of engagement will appear under the menu **ROE**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuROE( MenuTextFormat ) - self:F( MenuTextFormat ) - - if not self.EscortMenuROE then - -- Rules of Engagement - self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu ) - if self.EscortGroup:OptionROEHoldFirePossible() then - self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEHoldFire(), ParamMessage = "Holding weapons!" } ) - end - if self.EscortGroup:OptionROEReturnFirePossible() then - self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEReturnFire(), ParamMessage = "Returning fire!" } ) - end - if self.EscortGroup:OptionROEOpenFirePossible() then - self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEOpenFire(), ParamMessage = "Opening fire on designated targets!!" } ) - end - if self.EscortGroup:OptionROEWeaponFreePossible() then - self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROEWeaponFree(), ParamMessage = "Opening fire on targets of opportunity!" } ) - end - end - - return self -end - - ---- Defines a menu to let the escort set its evasion when under threat. --- All rules of engagement will appear under the menu **Evasion**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuEvasion( MenuTextFormat ) - self:F( MenuTextFormat ) - - if self.EscortGroup:IsAir() then - if not self.EscortMenuEvasion then - -- Reaction to Threats - self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu ) - if self.EscortGroup:OptionROTNoReactionPossible() then - self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTNoReaction(), ParamMessage = "Fighting until death!" } ) - end - if self.EscortGroup:OptionROTPassiveDefensePossible() then - self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTPassiveDefense(), ParamMessage = "Defending using jammers, chaff and flares!" } ) - end - if self.EscortGroup:OptionROTEvadeFirePossible() then - self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTEvadeFire(), ParamMessage = "Evading on enemy fire!" } ) - end - if self.EscortGroup:OptionROTVerticalPossible() then - self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, { ParamSelf = self, ParamFunction = self.EscortGroup:OptionROTVertical(), ParamMessage = "Evading on enemy fire with vertical manoeuvres!" } ) - end - end - end - - return self -end - ---- Defines a menu to let the escort resume its mission from a waypoint on its route. --- All rules of engagement will appear under the menu **Resume mission from**. --- @param #ESCORT self --- @return #ESCORT -function ESCORT:MenuResumeMission() - self:F() - - if not self.EscortMenuResumeMission then - -- Mission Resume Menu Root - self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu ) - end - - return self -end - - ---- @param #MENUPARAM MenuParam -function ESCORT._HoldPosition( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local OrbitGroup = MenuParam.ParamOrbitGroup -- Wrapper.Group#GROUP - local OrbitUnit = OrbitGroup:GetUnit(1) -- Wrapper.Unit#UNIT - local OrbitHeight = MenuParam.ParamHeight - local OrbitSeconds = MenuParam.ParamSeconds -- Not implemented yet - - self.FollowScheduler:Stop() - - local PointFrom = {} - local GroupVec3 = EscortGroup:GetUnit(1):GetVec3() - PointFrom = {} - PointFrom.x = GroupVec3.x - PointFrom.y = GroupVec3.z - PointFrom.speed = 250 - PointFrom.type = AI.Task.WaypointType.TURNING_POINT - PointFrom.alt = GroupVec3.y - PointFrom.alt_type = AI.Task.AltitudeType.BARO - - local OrbitPoint = OrbitUnit:GetVec2() - local PointTo = {} - PointTo.x = OrbitPoint.x - PointTo.y = OrbitPoint.y - PointTo.speed = 250 - PointTo.type = AI.Task.WaypointType.TURNING_POINT - PointTo.alt = OrbitHeight - PointTo.alt_type = AI.Task.AltitudeType.BARO - PointTo.task = EscortGroup:TaskOrbitCircleAtVec2( OrbitPoint, OrbitHeight, 0 ) - - local Points = { PointFrom, PointTo } - - EscortGroup:OptionROEHoldFire() - EscortGroup:OptionROTPassiveDefense() - - EscortGroup:SetTask( EscortGroup:TaskRoute( Points ) ) - EscortGroup:MessageToClient( "Orbiting at location.", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._JoinUpAndFollow( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self.Distance = MenuParam.ParamDistance - - self:JoinUpAndFollow( EscortGroup, EscortClient, self.Distance ) -end - ---- JoinsUp and Follows a CLIENT. --- @param Functional.Escort#ESCORT self --- @param Wrapper.Group#GROUP EscortGroup --- @param Wrapper.Client#CLIENT EscortClient --- @param Dcs.DCSTypes#Distance Distance -function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance ) - self:F( { EscortGroup, EscortClient, Distance } ) - - self.FollowScheduler:Stop() - - EscortGroup:OptionROEHoldFire() - EscortGroup:OptionROTPassiveDefense() - - self.EscortMode = ESCORT.MODE.FOLLOW - - self.CT1 = 0 - self.GT1 = 0 - self.FollowScheduler:Start() - - EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._Flare( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local Color = MenuParam.ParamColor - local Message = MenuParam.ParamMessage - - EscortGroup:GetUnit(1):Flare( Color ) - EscortGroup:MessageToClient( Message, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._Smoke( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local Color = MenuParam.ParamColor - local Message = MenuParam.ParamMessage - - EscortGroup:GetUnit(1):Smoke( Color ) - EscortGroup:MessageToClient( Message, 10, EscortClient ) -end - - ---- @param #MENUPARAM MenuParam -function ESCORT._ReportNearbyTargetsNow( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self:_ReportTargetsScheduler() - -end - -function ESCORT._SwitchReportNearbyTargets( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - self.ReportTargets = MenuParam.ParamReportTargets - - if self.ReportTargets then - if not self.ReportTargetsScheduler then - self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, 30 ) - end - else - routines.removeFunction( self.ReportTargetsScheduler ) - self.ReportTargetsScheduler = nil - end -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ScanTargets( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local ScanDuration = MenuParam.ParamScanDuration - - self.FollowScheduler:Stop() - - if EscortGroup:IsHelicopter() then - SCHEDULER:New( EscortGroup, EscortGroup.PushTask, - { EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 200, 20 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - 1 - ) - elseif EscortGroup:IsAirPlane() then - SCHEDULER:New( EscortGroup, EscortGroup.PushTask, - { EscortGroup:TaskControlled( - EscortGroup:TaskOrbitCircle( 1000, 500 ), - EscortGroup:TaskCondition( nil, nil, nil, nil, ScanDuration, nil ) - ) - }, - 1 - ) - end - - EscortGroup:MessageToClient( "Scanning targets for " .. ScanDuration .. " seconds.", ScanDuration, EscortClient ) - - if self.EscortMode == ESCORT.MODE.FOLLOW then - self.FollowScheduler:Start() - end - -end - ---- @param Wrapper.Group#GROUP EscortGroup -function _Resume( EscortGroup ) - env.info( '_Resume' ) - - local Escort = EscortGroup:GetState( EscortGroup, "Escort" ) - env.info( "EscortMode = " .. Escort.EscortMode ) - if Escort.EscortMode == ESCORT.MODE.FOLLOW then - Escort:JoinUpAndFollow( EscortGroup, Escort.EscortClient, Escort.Distance ) - end - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._AttackTarget( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - - local EscortClient = self.EscortClient - local AttackUnit = MenuParam.ParamUnit -- Wrapper.Unit#UNIT - - self.FollowScheduler:Stop() - - self:T( AttackUnit ) - - if EscortGroup:IsAir() then - EscortGroup:OptionROEOpenFire() - EscortGroup:OptionROTPassiveDefense() - EscortGroup:SetState( EscortGroup, "Escort", self ) - SCHEDULER:New( EscortGroup, - EscortGroup.PushTask, - { EscortGroup:TaskCombo( - { EscortGroup:TaskAttackUnit( AttackUnit ), - EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } ) - } - ) - }, 10 - ) - else - SCHEDULER:New( EscortGroup, - EscortGroup.PushTask, - { EscortGroup:TaskCombo( - { EscortGroup:TaskFireAtPoint( AttackUnit:GetVec2(), 50 ) - } - ) - }, 10 - ) - end - - EscortGroup:MessageToClient( "Engaging Designated Unit!", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._AssistTarget( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - local EscortGroupAttack = MenuParam.ParamEscortGroup - local AttackUnit = MenuParam.ParamUnit -- Wrapper.Unit#UNIT - - self.FollowScheduler:Stop() - - self:T( AttackUnit ) - - if EscortGroupAttack:IsAir() then - EscortGroupAttack:OptionROEOpenFire() - EscortGroupAttack:OptionROTVertical() - SCHDULER:New( EscortGroupAttack, - EscortGroupAttack.PushTask, - { EscortGroupAttack:TaskCombo( - { EscortGroupAttack:TaskAttackUnit( AttackUnit ), - EscortGroupAttack:TaskOrbitCircle( 500, 350 ) - } - ) - }, 10 - ) - else - SCHEDULER:New( EscortGroupAttack, - EscortGroupAttack.PushTask, - { EscortGroupAttack:TaskCombo( - { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetVec2(), 50 ) - } - ) - }, 10 - ) - end - EscortGroupAttack:MessageToClient( "Assisting with the destroying the enemy unit!", 10, EscortClient ) - -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ROE( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local EscortROEFunction = MenuParam.ParamFunction - local EscortROEMessage = MenuParam.ParamMessage - - pcall( function() EscortROEFunction() end ) - EscortGroup:MessageToClient( EscortROEMessage, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ROT( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local EscortROTFunction = MenuParam.ParamFunction - local EscortROTMessage = MenuParam.ParamMessage - - pcall( function() EscortROTFunction() end ) - EscortGroup:MessageToClient( EscortROTMessage, 10, EscortClient ) -end - ---- @param #MENUPARAM MenuParam -function ESCORT._ResumeMission( MenuParam ) - - local self = MenuParam.ParamSelf - local EscortGroup = self.EscortGroup - local EscortClient = self.EscortClient - - local WayPoint = MenuParam.ParamWayPoint - - self.FollowScheduler:Stop() - - local WayPoints = EscortGroup:GetTaskRoute() - self:T( WayPoint, WayPoints ) - - for WayPointIgnore = 1, WayPoint do - table.remove( WayPoints, 1 ) - end - - SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) - - EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) -end - ---- Registers the waypoints --- @param #ESCORT self --- @return #table -function ESCORT:RegisterRoute() - self:F() - - local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP - - local TaskPoints = EscortGroup:GetTaskRoute() - - self:T( TaskPoints ) - - return TaskPoints -end - ---- @param Functional.Escort#ESCORT self -function ESCORT:_FollowScheduler() - self:F( { self.FollowDistance } ) - - self:T( {self.EscortClient.UnitName, self.EscortGroup.GroupName } ) - if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then - - local ClientUnit = self.EscortClient:GetClientGroupUnit() - local GroupUnit = self.EscortGroup:GetUnit( 1 ) - local FollowDistance = self.FollowDistance - - self:T( {ClientUnit.UnitName, GroupUnit.UnitName } ) - - if self.CT1 == 0 and self.GT1 == 0 then - self.CV1 = ClientUnit:GetVec3() - self:T( { "self.CV1", self.CV1 } ) - self.CT1 = timer.getTime() - self.GV1 = GroupUnit:GetVec3() - self.GT1 = timer.getTime() - else - local CT1 = self.CT1 - local CT2 = timer.getTime() - local CV1 = self.CV1 - local CV2 = ClientUnit:GetVec3() - self.CT1 = CT2 - self.CV1 = CV2 - - local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 - local CT = CT2 - CT1 - - local CS = ( 3600 / CT ) * ( CD / 1000 ) - - self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) - - local GT1 = self.GT1 - local GT2 = timer.getTime() - local GV1 = self.GV1 - local GV2 = GroupUnit:GetVec3() - self.GT1 = GT2 - self.GV1 = GV2 - - local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 - local GT = GT2 - GT1 - - local GS = ( 3600 / GT ) * ( GD / 1000 ) - - self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) - - -- Calculate the group direction vector - local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } - - -- Calculate GH2, GH2 with the same height as CV2. - local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } - - -- Calculate the angle of GV to the orthonormal plane - local alpha = math.atan2( GV.z, GV.x ) - - -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. - -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) - local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), - y = GH2.y, - z = CV2.z + FollowDistance * math.sin(alpha), - } - - -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. - local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } - - -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. - -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. - -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... - local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } - - -- Now we can calculate the group destination vector GDV. - local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } - - if self.SmokeDirectionVector == true then - trigger.action.smoke( GDV, trigger.smokeColor.Red ) - end - - self:T2( { "CV2:", CV2 } ) - self:T2( { "CVI:", CVI } ) - self:T2( { "GDV:", GDV } ) - - -- Measure distance between client and group - local CatchUpDistance = ( ( GDV.x - GV2.x )^2 + ( GDV.y - GV2.y )^2 + ( GDV.z - GV2.z )^2 ) ^ 0.5 - - -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome - -- the requested Distance). - local Time = 10 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 8.4 ) ) / Time - - local Speed = CS + CatchUpSpeed - if Speed < 0 then - Speed = 0 - end - - self:T( { "Client Speed, Escort Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } ) - - -- Now route the escort to the desired point with the desired speed. - self.EscortGroup:TaskRouteToVec3( GDV, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) - end - - return true - end - - return false -end - - ---- Report Targets Scheduler. --- @param #ESCORT self -function ESCORT:_ReportTargetsScheduler() - self:F( self.EscortGroup:GetName() ) - - if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then - local EscortGroupName = self.EscortGroup:GetName() - local EscortTargets = self.EscortGroup:GetDetectedTargets() - - local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets - - local EscortTargetMessages = "" - for EscortTargetID, EscortTarget in pairs( EscortTargets ) do - local EscortObject = EscortTarget.object - self:T( EscortObject ) - if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then - - local EscortTargetUnit = UNIT:Find( EscortObject ) - local EscortTargetUnitName = EscortTargetUnit:GetName() - - - - -- local EscortTargetIsDetected, - -- EscortTargetIsVisible, - -- EscortTargetLastTime, - -- EscortTargetKnowType, - -- EscortTargetKnowDistance, - -- EscortTargetLastPos, - -- EscortTargetLastVelocity - -- = self.EscortGroup:IsTargetDetected( EscortObject ) - -- - -- self:T( { EscortTargetIsDetected, - -- EscortTargetIsVisible, - -- EscortTargetLastTime, - -- EscortTargetKnowType, - -- EscortTargetKnowDistance, - -- EscortTargetLastPos, - -- EscortTargetLastVelocity } ) - - - local EscortTargetUnitVec3 = EscortTargetUnit:GetVec3() - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + - ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + - ( EscortTargetUnitVec3.z - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } ) - - if Distance <= 15 then - - if not ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = {} - end - ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit - ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible - ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type - ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance - else - if ClientEscortTargets[EscortTargetUnitName] then - ClientEscortTargets[EscortTargetUnitName] = nil - end - end - end - end - - self:T( { "Sorting Targets Table:", ClientEscortTargets } ) - table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end ) - self:T( { "Sorted Targets Table:", ClientEscortTargets } ) - - -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup. - self.EscortMenuAttackNearbyTargets:RemoveSubMenus() - - if self.EscortMenuTargetAssistance then - self.EscortMenuTargetAssistance:RemoveSubMenus() - end - - --for MenuIndex = 1, #self.EscortMenuAttackTargets do - -- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } ) - -- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove() - --end - - - if ClientEscortTargets then - for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do - - for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do - - if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then - - local EscortTargetMessage = "" - local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName() - local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName() - if ClientEscortTargetData.type then - EscortTargetMessage = EscortTargetMessage .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at " - else - EscortTargetMessage = EscortTargetMessage .. "Unknown target at " - end - - local EscortTargetUnitVec3 = ClientEscortTargetData.AttackUnit:GetVec3() - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 + - ( EscortTargetUnitVec3.y - EscortVec3.y )^2 + - ( EscortTargetUnitVec3.z - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } ) - if ClientEscortTargetData.visible == false then - EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km" - else - EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km" - end - - if ClientEscortTargetData.visible then - EscortTargetMessage = EscortTargetMessage .. ", visual" - end - - if ClientEscortGroupName == EscortGroupName then - - MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - self.EscortMenuAttackNearbyTargets, - ESCORT._AttackTarget, - { ParamSelf = self, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) - EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage - else - if self.EscortMenuTargetAssistance then - local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance ) - MENU_CLIENT_COMMAND:New( self.EscortClient, - EscortTargetMessage, - MenuTargetAssistance, - ESCORT._AssistTarget, - { ParamSelf = self, - ParamEscortGroup = EscortGroupData.EscortGroup, - ParamUnit = ClientEscortTargetData.AttackUnit - } - ) - end - end - else - ClientEscortTargetData = nil - end - end - end - - if EscortTargetMessages ~= "" and self.ReportTargets == true then - self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient ) - else - self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient ) - end - end - - if self.EscortMenuResumeMission then - self.EscortMenuResumeMission:RemoveSubMenus() - - -- if self.EscortMenuResumeWayPoints then - -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do - -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } ) - -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove() - -- end - -- end - - local TaskPoints = self:RegisterRoute() - for WayPointID, WayPoint in pairs( TaskPoints ) do - local EscortVec3 = self.EscortGroup:GetVec3() - local Distance = ( ( WayPoint.x - EscortVec3.x )^2 + - ( WayPoint.y - EscortVec3.z )^2 - ) ^ 0.5 / 1000 - MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } ) - end - end - - return true - end - - return false -end ---- This module contains the MISSILETRAINER class. --- --- === --- --- 1) @{Functional.MissileTrainer#MISSILETRAINER} class, extends @{Core.Base#BASE} --- =============================================================== --- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft, --- the class will destroy the missile within a certain range, to avoid damage to your aircraft. --- It suports the following functionality: --- --- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes. --- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range � --- * Provide alerts when a missile would have killed your aircraft. --- * Provide alerts when the missile self destructs. --- * Enable / Disable and Configure the Missile Trainer using the various menu options. --- --- When running a mission where MISSILETRAINER is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players: --- --- * **Messages**: Menu to configure all messages. --- * **Messages On**: Show all messages. --- * **Messages Off**: Disable all messages. --- * **Tracking**: Menu to configure missile tracking messages. --- * **To All**: Shows missile tracking messages to all players. --- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at. --- * **Tracking On**: Show missile tracking messages. --- * **Tracking Off**: Disable missile tracking messages. --- * **Frequency Increase**: Increases the missile tracking message frequency with one second. --- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second. --- * **Alerts**: Menu to configure alert messages. --- * **To All**: Shows alert messages to all players. --- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at. --- * **Hits On**: Show missile hit alert messages. --- * **Hits Off**: Disable missile hit alert messages. --- * **Launches On**: Show missile launch messages. --- * **Launches Off**: Disable missile launch messages. --- * **Details**: Menu to configure message details. --- * **Range On**: Shows range information when a missile is fired to a target. --- * **Range Off**: Disable range information when a missile is fired to a target. --- * **Bearing On**: Shows bearing information when a missile is fired to a target. --- * **Bearing Off**: Disable bearing information when a missile is fired to a target. --- * **Distance**: Menu to configure the distance when a missile needs to be destroyed when near to a player, during tracking. This will improve/influence hit calculation accuracy, but has the risk of damaging the aircraft when the missile reaches the aircraft before the distance is measured. --- * **50 meter**: Destroys the missile when the distance to the aircraft is below or equal to 50 meter. --- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter. --- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter. --- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter. --- --- --- 1.1) MISSILETRAINER construction methods: --- ----------------------------------------- --- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method: --- --- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed. --- --- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those. --- --- 1.2) MISSILETRAINER initialization methods: --- ------------------------------------------- --- A MISSILETRAINER object will behave differently based on the usage of initialization methods: --- --- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF. --- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you. --- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF. --- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. --- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you. --- * @{#MISSILETRAINER.InitAlertsHitsOnOff}: Sets by default the display of hit alerts ON or OFF. --- * @{#MISSILETRAINER.InitAlertsLaunchesOnOff}: Sets by default the display of launch alerts ON or OFF. --- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF. --- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF. --- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu. --- --- === --- --- CREDITS --- ======= --- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums. --- Working together with Danny has resulted in the MISSILETRAINER class. --- Danny has shared his ideas and together we made a design. --- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback! --- --- @module MissileTrainer --- @author FlightControl - - ---- The MISSILETRAINER class --- @type MISSILETRAINER --- @field Core.Set#SET_CLIENT DBClients --- @extends Core.Base#BASE -MISSILETRAINER = { - ClassName = "MISSILETRAINER", - TrackingMissiles = {}, -} - -function MISSILETRAINER._Alive( Client, self ) - - if self.Briefing then - Client:Message( self.Briefing, 15, "Trainer" ) - end - - if self.MenusOnOff == true then - Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" ) - - Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT - - Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu ) - Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } ) - Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } ) - - Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu ) - Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } ) - Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } ) - Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } ) - Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } ) - Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } ) - Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } ) - - Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu ) - Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } ) - Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } ) - Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } ) - Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } ) - Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } ) - Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } ) - - Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu ) - Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } ) - Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } ) - Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } ) - Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } ) - - Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu ) - Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } ) - Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } ) - Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } ) - Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } ) - else - if Client.MainMenu then - Client.MainMenu:Remove() - end - end - - local ClientID = Client:GetID() - self:T( ClientID ) - if not self.TrackingMissiles[ClientID] then - self.TrackingMissiles[ClientID] = {} - end - self.TrackingMissiles[ClientID].Client = Client - if not self.TrackingMissiles[ClientID].MissileData then - self.TrackingMissiles[ClientID].MissileData = {} - end -end - ---- Creates the main object which is handling missile tracking. --- When a missile is fired a SCHEDULER is set off that follows the missile. When near a certain a client player, the missile will be destroyed. --- @param #MISSILETRAINER self --- @param #number Distance The distance in meters when a tracked missile needs to be destroyed when close to a player. --- @param #string Briefing (Optional) Will show a text to the players when starting their mission. Can be used for briefing purposes. --- @return #MISSILETRAINER -function MISSILETRAINER:New( Distance, Briefing ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( Distance ) - - if Briefing then - self.Briefing = Briefing - end - - self.Schedulers = {} - self.SchedulerID = 0 - - self.MessageInterval = 2 - self.MessageLastTime = timer.getTime() - - self.Distance = Distance / 1000 - - _EVENTDISPATCHER:OnShot( self._EventShot, self ) - - self.DBClients = SET_CLIENT:New():FilterStart() - - --- for ClientID, Client in pairs( self.DBClients.Database ) do --- self:E( "ForEach:" .. Client.UnitName ) --- Client:Alive( self._Alive, self ) --- end --- - self.DBClients:ForEachClient( - function( Client ) - self:E( "ForEach:" .. Client.UnitName ) - Client:Alive( self._Alive, self ) - end - ) - - - --- self.DB:ForEachClient( --- --- @param Wrapper.Client#CLIENT Client --- function( Client ) --- --- ... actions ... --- --- end --- ) - - self.MessagesOnOff = true - - self.TrackingToAll = false - self.TrackingOnOff = true - self.TrackingFrequency = 3 - - self.AlertsToAll = true - self.AlertsHitsOnOff = true - self.AlertsLaunchesOnOff = true - - self.DetailsRangeOnOff = true - self.DetailsBearingOnOff = true - - self.MenusOnOff = true - - self.TrackingMissiles = {} - - self.TrackingScheduler = SCHEDULER:New( self, self._TrackMissiles, {}, 0.5, 0.05, 0 ) - - return self -end - --- Initialization methods. - - - ---- Sets by default the display of any message to be ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean MessagesOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff ) - self:F( MessagesOnOff ) - - self.MessagesOnOff = MessagesOnOff - if self.MessagesOnOff == true then - MESSAGE:New( "Messages ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Messages OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the missile tracking report for all players or only for those missiles targetted to you. --- @param #MISSILETRAINER self --- @param #boolean TrackingToAll true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingToAll( TrackingToAll ) - self:F( TrackingToAll ) - - self.TrackingToAll = TrackingToAll - if self.TrackingToAll == true then - MESSAGE:New( "Missile tracking to all players ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Missile tracking to all players OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of missile tracking report to be ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean TrackingOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingOnOff( TrackingOnOff ) - self:F( TrackingOnOff ) - - self.TrackingOnOff = TrackingOnOff - if self.TrackingOnOff == true then - MESSAGE:New( "Missile tracking ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Missile tracking OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Increases, decreases the missile tracking message display frequency with the provided time interval in seconds. --- The default frequency is a 3 second interval, so the Tracking Frequency parameter specifies the increase or decrease from the default 3 seconds or the last frequency update. --- @param #MISSILETRAINER self --- @param #number TrackingFrequency Provide a negative or positive value in seconds to incraese or decrease the display frequency. --- @return #MISSILETRAINER self -function MISSILETRAINER:InitTrackingFrequency( TrackingFrequency ) - self:F( TrackingFrequency ) - - self.TrackingFrequency = self.TrackingFrequency + TrackingFrequency - if self.TrackingFrequency < 0.5 then - self.TrackingFrequency = 0.5 - end - if self.TrackingFrequency then - MESSAGE:New( "Missile tracking frequency is " .. self.TrackingFrequency .. " seconds.", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of alerts to be shown to all players or only to you. --- @param #MISSILETRAINER self --- @param #boolean AlertsToAll true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsToAll( AlertsToAll ) - self:F( AlertsToAll ) - - self.AlertsToAll = AlertsToAll - if self.AlertsToAll == true then - MESSAGE:New( "Alerts to all players ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts to all players OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of hit alerts ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean AlertsHitsOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsHitsOnOff( AlertsHitsOnOff ) - self:F( AlertsHitsOnOff ) - - self.AlertsHitsOnOff = AlertsHitsOnOff - if self.AlertsHitsOnOff == true then - MESSAGE:New( "Alerts Hits ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts Hits OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of launch alerts ON or OFF. --- @param #MISSILETRAINER self --- @param #boolean AlertsLaunchesOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitAlertsLaunchesOnOff( AlertsLaunchesOnOff ) - self:F( AlertsLaunchesOnOff ) - - self.AlertsLaunchesOnOff = AlertsLaunchesOnOff - if self.AlertsLaunchesOnOff == true then - MESSAGE:New( "Alerts Launches ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Alerts Launches OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of range information of missiles ON of OFF. --- @param #MISSILETRAINER self --- @param #boolean DetailsRangeOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitRangeOnOff( DetailsRangeOnOff ) - self:F( DetailsRangeOnOff ) - - self.DetailsRangeOnOff = DetailsRangeOnOff - if self.DetailsRangeOnOff == true then - MESSAGE:New( "Range display ON", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Range display OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Sets by default the display of bearing information of missiles ON of OFF. --- @param #MISSILETRAINER self --- @param #boolean DetailsBearingOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitBearingOnOff( DetailsBearingOnOff ) - self:F( DetailsBearingOnOff ) - - self.DetailsBearingOnOff = DetailsBearingOnOff - if self.DetailsBearingOnOff == true then - MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Bearing display OFF", 15, "Menu" ):ToAll() - end - - return self -end - ---- Enables / Disables the menus. --- @param #MISSILETRAINER self --- @param #boolean MenusOnOff true or false --- @return #MISSILETRAINER self -function MISSILETRAINER:InitMenusOnOff( MenusOnOff ) - self:F( MenusOnOff ) - - self.MenusOnOff = MenusOnOff - if self.MenusOnOff == true then - MESSAGE:New( "Menus are ENABLED (only when a player rejoins a slot)", 15, "Menu" ):ToAll() - else - MESSAGE:New( "Menus are DISABLED", 15, "Menu" ):ToAll() - end - - return self -end - - --- Menu functions - -function MISSILETRAINER._MenuMessages( MenuParameters ) - - local self = MenuParameters.MenuSelf - - if MenuParameters.MessagesOnOff ~= nil then - self:InitMessagesOnOff( MenuParameters.MessagesOnOff ) - end - - if MenuParameters.TrackingToAll ~= nil then - self:InitTrackingToAll( MenuParameters.TrackingToAll ) - end - - if MenuParameters.TrackingOnOff ~= nil then - self:InitTrackingOnOff( MenuParameters.TrackingOnOff ) - end - - if MenuParameters.TrackingFrequency ~= nil then - self:InitTrackingFrequency( MenuParameters.TrackingFrequency ) - end - - if MenuParameters.AlertsToAll ~= nil then - self:InitAlertsToAll( MenuParameters.AlertsToAll ) - end - - if MenuParameters.AlertsHitsOnOff ~= nil then - self:InitAlertsHitsOnOff( MenuParameters.AlertsHitsOnOff ) - end - - if MenuParameters.AlertsLaunchesOnOff ~= nil then - self:InitAlertsLaunchesOnOff( MenuParameters.AlertsLaunchesOnOff ) - end - - if MenuParameters.DetailsRangeOnOff ~= nil then - self:InitRangeOnOff( MenuParameters.DetailsRangeOnOff ) - end - - if MenuParameters.DetailsBearingOnOff ~= nil then - self:InitBearingOnOff( MenuParameters.DetailsBearingOnOff ) - end - - if MenuParameters.Distance ~= nil then - self.Distance = MenuParameters.Distance - MESSAGE:New( "Hit detection distance set to " .. self.Distance .. " meters", 15, "Menu" ):ToAll() - end - -end - ---- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME. --- @param #MISSILETRAINER self --- @param Core.Event#EVENTDATA Event -function MISSILETRAINER:_EventShot( Event ) - self:F( { Event } ) - - local TrainerSourceDCSUnit = Event.IniDCSUnit - local TrainerSourceDCSUnitName = Event.IniDCSUnitName - local TrainerWeapon = Event.Weapon -- Identify the weapon fired - local TrainerWeaponName = Event.WeaponName -- return weapon type - - self:T( "Missile Launched = " .. TrainerWeaponName ) - - local TrainerTargetDCSUnit = TrainerWeapon:getTarget() -- Identify target - if TrainerTargetDCSUnit then - local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit ) - local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill - - self:T(TrainerTargetDCSUnitName ) - - local Client = self.DBClients:FindClient( TrainerTargetDCSUnitName ) - if Client then - - local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit ) - local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit ) - - if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then - - local Message = MESSAGE:New( - string.format( "%s launched a %s", - TrainerSourceUnit:GetTypeName(), - TrainerWeaponName - ) .. self:_AddRange( Client, TrainerWeapon ) .. self:_AddBearing( Client, TrainerWeapon ), 5, "Launch Alert" ) - - if self.AlertsToAll then - Message:ToAll() - else - Message:ToClient( Client ) - end - end - - local ClientID = Client:GetID() - self:T( ClientID ) - local MissileData = {} - MissileData.TrainerSourceUnit = TrainerSourceUnit - MissileData.TrainerWeapon = TrainerWeapon - MissileData.TrainerTargetUnit = TrainerTargetUnit - MissileData.TrainerWeaponTypeName = TrainerWeapon:getTypeName() - MissileData.TrainerWeaponLaunched = true - table.insert( self.TrackingMissiles[ClientID].MissileData, MissileData ) - --self:T( self.TrackingMissiles ) - end - else - -- TODO: some weapons don't know the target unit... Need to develop a workaround for this. - SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) - if ( TrainerWeapon:getTypeName() == "9M311" ) then - SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) - else - end - end -end - -function MISSILETRAINER:_AddRange( Client, TrainerWeapon ) - - local RangeText = "" - - if self.DetailsRangeOnOff then - - local PositionMissile = TrainerWeapon:getPoint() - local TargetVec3 = Client:GetVec3() - - local Range = ( ( PositionMissile.x - TargetVec3.x )^2 + - ( PositionMissile.y - TargetVec3.y )^2 + - ( PositionMissile.z - TargetVec3.z )^2 - ) ^ 0.5 / 1000 - - RangeText = string.format( ", at %4.2fkm", Range ) - end - - return RangeText -end - -function MISSILETRAINER:_AddBearing( Client, TrainerWeapon ) - - local BearingText = "" - - if self.DetailsBearingOnOff then - - local PositionMissile = TrainerWeapon:getPoint() - local TargetVec3 = Client:GetVec3() - - self:T2( { TargetVec3, PositionMissile }) - - local DirectionVector = { x = PositionMissile.x - TargetVec3.x, y = PositionMissile.y - TargetVec3.y, z = PositionMissile.z - TargetVec3.z } - local DirectionRadians = math.atan2( DirectionVector.z, DirectionVector.x ) - --DirectionRadians = DirectionRadians + routines.getNorthCorrection( PositionTarget ) - if DirectionRadians < 0 then - DirectionRadians = DirectionRadians + 2 * math.pi - end - local DirectionDegrees = DirectionRadians * 180 / math.pi - - BearingText = string.format( ", %d degrees", DirectionDegrees ) - end - - return BearingText -end - - -function MISSILETRAINER:_TrackMissiles() - self:F2() - - - local ShowMessages = false - if self.MessagesOnOff and self.MessageLastTime + self.TrackingFrequency <= timer.getTime() then - self.MessageLastTime = timer.getTime() - ShowMessages = true - end - - -- ALERTS PART - - -- Loop for all Player Clients to check the alerts and deletion of missiles. - for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do - - local Client = ClientData.Client - self:T2( { Client:GetName() } ) - - for MissileDataID, MissileData in pairs( ClientData.MissileData ) do - self:T3( MissileDataID ) - - local TrainerSourceUnit = MissileData.TrainerSourceUnit - local TrainerWeapon = MissileData.TrainerWeapon - local TrainerTargetUnit = MissileData.TrainerTargetUnit - local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName - local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched - - if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then - local PositionMissile = TrainerWeapon:getPosition().p - local TargetVec3 = Client:GetVec3() - - local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 + - ( PositionMissile.y - TargetVec3.y )^2 + - ( PositionMissile.z - TargetVec3.z )^2 - ) ^ 0.5 / 1000 - - if Distance <= self.Distance then - -- Hit alert - TrainerWeapon:destroy() - if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then - - self:T( "killed" ) - - local Message = MESSAGE:New( - string.format( "%s launched by %s killed %s", - TrainerWeapon:getTypeName(), - TrainerSourceUnit:GetTypeName(), - TrainerTargetUnit:GetPlayerName() - ), 15, "Hit Alert" ) - - if self.AlertsToAll == true then - Message:ToAll() - else - Message:ToClient( Client ) - end - - MissileData = nil - table.remove( ClientData.MissileData, MissileDataID ) - self:T(ClientData.MissileData) - end - end - else - if not ( TrainerWeapon and TrainerWeapon:isExist() ) then - if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then - -- Weapon does not exist anymore. Delete from Table - local Message = MESSAGE:New( - string.format( "%s launched by %s self destructed!", - TrainerWeaponTypeName, - TrainerSourceUnit:GetTypeName() - ), 5, "Tracking" ) - - if self.AlertsToAll == true then - Message:ToAll() - else - Message:ToClient( Client ) - end - end - MissileData = nil - table.remove( ClientData.MissileData, MissileDataID ) - self:T( ClientData.MissileData ) - end - end - end - end - - if ShowMessages == true and self.MessagesOnOff == true and self.TrackingOnOff == true then -- Only do this when tracking information needs to be displayed. - - -- TRACKING PART - - -- For the current client, the missile range and bearing details are displayed To the Player Client. - -- For the other clients, the missile range and bearing details are displayed To the other Player Clients. - -- To achieve this, a cross loop is done for each Player Client <-> Other Player Client missile information. - - -- Main Player Client loop - for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do - - local Client = ClientData.Client - self:T2( { Client:GetName() } ) - - - ClientData.MessageToClient = "" - ClientData.MessageToAll = "" - - -- Other Players Client loop - for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do - - for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do - self:T3( MissileDataID ) - - local TrainerSourceUnit = MissileData.TrainerSourceUnit - local TrainerWeapon = MissileData.TrainerWeapon - local TrainerTargetUnit = MissileData.TrainerTargetUnit - local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName - local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched - - if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then - - if ShowMessages == true then - local TrackingTo - TrackingTo = string.format( " -> %s", - TrainerWeaponTypeName - ) - - if ClientDataID == TrackingDataID then - if ClientData.MessageToClient == "" then - ClientData.MessageToClient = "Missiles to You:\n" - end - ClientData.MessageToClient = ClientData.MessageToClient .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. "\n" - else - if self.TrackingToAll == true then - if ClientData.MessageToAll == "" then - ClientData.MessageToAll = "Missiles to other Players:\n" - end - ClientData.MessageToAll = ClientData.MessageToAll .. TrackingTo .. self:_AddRange( ClientData.Client, TrainerWeapon ) .. self:_AddBearing( ClientData.Client, TrainerWeapon ) .. " ( " .. TrainerTargetUnit:GetPlayerName() .. " )\n" - end - end - end - end - end - end - - -- Once the Player Client and the Other Player Client tracking messages are prepared, show them. - if ClientData.MessageToClient ~= "" or ClientData.MessageToAll ~= "" then - local Message = MESSAGE:New( ClientData.MessageToClient .. ClientData.MessageToAll, 1, "Tracking" ):ToClient( Client ) - end - end - end - - return true -end ---- This module contains the AIRBASEPOLICE classes. --- --- === --- --- 1) @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} class, extends @{Core.Base#BASE} --- ================================================================== --- The @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} class provides the main methods to monitor CLIENT behaviour at airbases. --- CLIENTS should not be allowed to: --- --- * Don't taxi faster than 40 km/h. --- * Don't take-off on taxiways. --- * Avoid to hit other planes on the airbase. --- * Obey ground control orders. --- --- 2) @{Functional.AirbasePolice#AIRBASEPOLICE_CAUCASUS} class, extends @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} --- ============================================================================================= --- All the airbases on the caucasus map can be monitored using this class. --- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. --- The following names can be given: --- * AnapaVityazevo --- * Batumi --- * Beslan --- * Gelendzhik --- * Gudauta --- * Kobuleti --- * KrasnodarCenter --- * KrasnodarPashkovsky --- * Krymsk --- * Kutaisi --- * MaykopKhanskaya --- * MineralnyeVody --- * Mozdok --- * Nalchik --- * Novorossiysk --- * SenakiKolkhi --- * SochiAdler --- * Soganlug --- * SukhumiBabushara --- * TbilisiLochini --- * Vaziani --- --- 3) @{Functional.AirbasePolice#AIRBASEPOLICE_NEVADA} class, extends @{Functional.AirbasePolice#AIRBASEPOLICE_BASE} --- ============================================================================================= --- All the airbases on the NEVADA map can be monitored using this class. --- If you want to monitor specific airbases, you need to use the @{#AIRBASEPOLICE_BASE.Monitor}() method, which takes a table or airbase names. --- The following names can be given: --- * Nellis --- * McCarran --- * Creech --- * Groom Lake --- --- ### Contributions: Dutch Baron - Concept & Testing --- ### Author: FlightControl - Framework Design & Programming --- --- @module AirbasePolice - - - - - ---- @type AIRBASEPOLICE_BASE --- @field Core.Set#SET_CLIENT SetClient --- @extends Core.Base#BASE - -AIRBASEPOLICE_BASE = { - ClassName = "AIRBASEPOLICE_BASE", - SetClient = nil, - Airbases = nil, - AirbaseNames = nil, -} - - ---- Creates a new AIRBASEPOLICE_BASE object. --- @param #AIRBASEPOLICE_BASE self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @param Airbases A table of Airbase Names. --- @return #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:New( SetClient, Airbases ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - self:E( { self.ClassName, SetClient, Airbases } ) - - self.SetClient = SetClient - self.Airbases = Airbases - - for AirbaseID, Airbase in pairs( self.Airbases ) do - Airbase.ZoneBoundary = ZONE_POLYGON_BASE:New( "Boundary", Airbase.PointsBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - for PointsRunwayID, PointsRunway in pairs( Airbase.PointsRunways ) do - Airbase.ZoneRunways[PointsRunwayID] = ZONE_POLYGON_BASE:New( "Runway " .. PointsRunwayID, PointsRunway ):SmokeZone(SMOKECOLOR.Red):Flush() - end - end - --- -- Template --- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) --- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) --- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - - self.SetClient:ForEachClient( - --- @param Wrapper.Client#CLIENT Client - function( Client ) - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0) - Client:SetState( self, "Taxi", false ) - end - ) - - self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, {}, 0, 2, 0.05 ) - - return self -end - ---- @type AIRBASEPOLICE_BASE.AirbaseNames --- @list <#string> - ---- Monitor a table of airbase names. --- @param #AIRBASEPOLICE_BASE self --- @param #AIRBASEPOLICE_BASE.AirbaseNames AirbaseNames A list of AirbaseNames to monitor. If this parameters is nil, then all airbases will be monitored. --- @return #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:Monitor( AirbaseNames ) - - if AirbaseNames then - if type( AirbaseNames ) == "table" then - self.AirbaseNames = AirbaseNames - else - self.AirbaseNames = { AirbaseNames } - end - end -end - ---- @param #AIRBASEPOLICE_BASE self -function AIRBASEPOLICE_BASE:_AirbaseMonitor() - - for AirbaseID, Airbase in pairs( self.Airbases ) do - - if not self.AirbaseNames or self.AirbaseNames[AirbaseID] then - - self:E( AirbaseID ) - - self.SetClient:ForEachClientInZone( Airbase.ZoneBoundary, - - --- @param Wrapper.Client#CLIENT Client - function( Client ) - - self:E( Client.UnitName ) - if Client:IsAlive() then - local NotInRunwayZone = true - for ZoneRunwayID, ZoneRunway in pairs( Airbase.ZoneRunways ) do - NotInRunwayZone = ( Client:IsNotInZone( ZoneRunway ) == true ) and NotInRunwayZone or false - end - - if NotInRunwayZone then - local Taxi = self:GetState( self, "Taxi" ) - self:E( Taxi ) - if Taxi == false then - Client:Message( "Welcome at " .. AirbaseID .. ". The maximum taxiing speed is " .. Airbase.MaximumSpeed " km/h.", 20, "ATC" ) - self:SetState( self, "Taxi", true ) - end - - -- TODO: GetVelocityKMH function usage - local VelocityVec3 = Client:GetVelocity() - local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - local Velocity = Velocity * 3.6 -- now it is in km/h. - -- MESSAGE:New( "Velocity = " .. Velocity, 1 ):ToAll() - local IsAboveRunway = Client:IsAboveRunway() - local IsOnGround = Client:InAir() == false - self:T( IsAboveRunway, IsOnGround ) - - if IsAboveRunway and IsOnGround then - - if Velocity > Airbase.MaximumSpeed then - local IsSpeeding = Client:GetState( self, "Speeding" ) - - if IsSpeeding == true then - local SpeedingWarnings = Client:GetState( self, "Warnings" ) - self:T( SpeedingWarnings ) - - if SpeedingWarnings <= 3 then - Client:Message( "You are speeding on the taxiway! Slow down or you will be removed from this airbase! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Warning " .. SpeedingWarnings .. " / 3" ) - Client:SetState( self, "Warnings", SpeedingWarnings + 1 ) - else - MESSAGE:New( "Player " .. Client:GetPlayerName() .. " has been removed from the airbase, due to a speeding violation ...", 10, "Airbase Police" ):ToAll() - Client:GetGroup():Destroy() - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - end - - else - Client:Message( "You are speeding on the taxiway, slow down now! Your current velocity is " .. string.format( "%2.0f km/h", Velocity ), 5, "Attention! " ) - Client:SetState( self, "Speeding", true ) - Client:SetState( self, "Warnings", 1 ) - end - - else - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - end - end - - else - Client:SetState( self, "Speeding", false ) - Client:SetState( self, "Warnings", 0 ) - local Taxi = self:GetState( self, "Taxi" ) - if Taxi == true then - Client:Message( "You have progressed to the runway ... Await take-off clearance ...", 20, "ATC" ) - self:SetState( self, "Taxi", false ) - end - end - end - end - ) - end - end - - return true -end - - ---- @type AIRBASEPOLICE_CAUCASUS --- @field Core.Set#SET_CLIENT SetClient --- @extends #AIRBASEPOLICE_BASE - -AIRBASEPOLICE_CAUCASUS = { - ClassName = "AIRBASEPOLICE_CAUCASUS", - Airbases = { - AnapaVityazevo = { - PointsBoundary = { - [1]={["y"]=242234.85714287,["x"]=-6616.5714285726,}, - [2]={["y"]=241060.57142858,["x"]=-5585.142857144,}, - [3]={["y"]=243806.2857143,["x"]=-3962.2857142868,}, - [4]={["y"]=245240.57142858,["x"]=-4816.5714285726,}, - [5]={["y"]=244783.42857144,["x"]=-5630.8571428583,}, - [6]={["y"]=243800.57142858,["x"]=-5065.142857144,}, - [7]={["y"]=242232.00000001,["x"]=-6622.2857142868,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=242140.57142858,["x"]=-6478.8571428583,}, - [2]={["y"]=242188.57142858,["x"]=-6522.0000000011,}, - [3]={["y"]=244124.2857143,["x"]=-4344.0000000011,}, - [4]={["y"]=244068.2857143,["x"]=-4296.5714285726,}, - [5]={["y"]=242140.57142858,["x"]=-6480.0000000011,} - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Batumi = { - PointsBoundary = { - [1]={["y"]=617567.14285714,["x"]=-355313.14285715,}, - [2]={["y"]=616181.42857142,["x"]=-354800.28571429,}, - [3]={["y"]=616007.14285714,["x"]=-355128.85714286,}, - [4]={["y"]=618230,["x"]=-356914.57142858,}, - [5]={["y"]=618727.14285714,["x"]=-356166,}, - [6]={["y"]=617572.85714285,["x"]=-355308.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=616442.28571429,["x"]=-355090.28571429,}, - [2]={["y"]=618450.57142857,["x"]=-356522,}, - [3]={["y"]=618407.71428571,["x"]=-356584.85714286,}, - [4]={["y"]=618361.99999999,["x"]=-356554.85714286,}, - [5]={["y"]=618324.85714285,["x"]=-356599.14285715,}, - [6]={["y"]=618250.57142856,["x"]=-356543.42857143,}, - [7]={["y"]=618257.7142857,["x"]=-356496.28571429,}, - [8]={["y"]=618237.7142857,["x"]=-356459.14285715,}, - [9]={["y"]=616555.71428571,["x"]=-355258.85714286,}, - [10]={["y"]=616486.28571428,["x"]=-355280.57142858,}, - [11]={["y"]=616410.57142856,["x"]=-355227.71428572,}, - [12]={["y"]=616441.99999999,["x"]=-355179.14285715,}, - [13]={["y"]=616401.99999999,["x"]=-355147.71428572,}, - [14]={["y"]=616441.42857142,["x"]=-355092.57142858,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Beslan = { - PointsBoundary = { - [1]={["y"]=842082.57142857,["x"]=-148445.14285715,}, - [2]={["y"]=845237.71428572,["x"]=-148639.71428572,}, - [3]={["y"]=845232,["x"]=-148765.42857143,}, - [4]={["y"]=844220.57142857,["x"]=-149168.28571429,}, - [5]={["y"]=843274.85714286,["x"]=-149125.42857143,}, - [6]={["y"]=842077.71428572,["x"]=-148554,}, - [7]={["y"]=842083.42857143,["x"]=-148445.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=842104.57142857,["x"]=-148460.57142857,}, - [2]={["y"]=845225.71428572,["x"]=-148656,}, - [3]={["y"]=845220.57142858,["x"]=-148750,}, - [4]={["y"]=842098.85714286,["x"]=-148556.28571429,}, - [5]={["y"]=842104,["x"]=-148460.28571429,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Gelendzhik = { - PointsBoundary = { - [1]={["y"]=297856.00000001,["x"]=-51151.428571429,}, - [2]={["y"]=299044.57142858,["x"]=-49720.000000001,}, - [3]={["y"]=298861.71428572,["x"]=-49580.000000001,}, - [4]={["y"]=298198.85714286,["x"]=-49842.857142858,}, - [5]={["y"]=297990.28571429,["x"]=-50151.428571429,}, - [6]={["y"]=297696.00000001,["x"]=-51054.285714286,}, - [7]={["y"]=297850.28571429,["x"]=-51160.000000001,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=297834.00000001,["x"]=-51107.428571429,}, - [2]={["y"]=297786.57142858,["x"]=-51068.857142858,}, - [3]={["y"]=298946.57142858,["x"]=-49686.000000001,}, - [4]={["y"]=298993.14285715,["x"]=-49725.714285715,}, - [5]={["y"]=297835.14285715,["x"]=-51107.714285715,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Gudauta = { - PointsBoundary = { - [1]={["y"]=517246.57142857,["x"]=-197850.28571429,}, - [2]={["y"]=516749.42857142,["x"]=-198070.28571429,}, - [3]={["y"]=515755.14285714,["x"]=-197598.85714286,}, - [4]={["y"]=515369.42857142,["x"]=-196538.85714286,}, - [5]={["y"]=515623.71428571,["x"]=-195618.85714286,}, - [6]={["y"]=515946.57142857,["x"]=-195510.28571429,}, - [7]={["y"]=517243.71428571,["x"]=-197858.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=517096.57142857,["x"]=-197804.57142857,}, - [2]={["y"]=515880.85714285,["x"]=-195590.28571429,}, - [3]={["y"]=515812.28571428,["x"]=-195628.85714286,}, - [4]={["y"]=517036.57142857,["x"]=-197834.57142857,}, - [5]={["y"]=517097.99999999,["x"]=-197807.42857143,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Kobuleti = { - PointsBoundary = { - [1]={["y"]=634427.71428571,["x"]=-318290.28571429,}, - [2]={["y"]=635033.42857143,["x"]=-317550.2857143,}, - [3]={["y"]=635864.85714286,["x"]=-317333.14285715,}, - [4]={["y"]=636967.71428571,["x"]=-317261.71428572,}, - [5]={["y"]=637144.85714286,["x"]=-317913.14285715,}, - [6]={["y"]=634630.57142857,["x"]=-318687.42857144,}, - [7]={["y"]=634424.85714286,["x"]=-318290.2857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=634509.71428571,["x"]=-318339.42857144,}, - [2]={["y"]=636767.42857143,["x"]=-317516.57142858,}, - [3]={["y"]=636790,["x"]=-317575.71428572,}, - [4]={["y"]=634531.42857143,["x"]=-318398.00000001,}, - [5]={["y"]=634510.28571429,["x"]=-318339.71428572,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - KrasnodarCenter = { - PointsBoundary = { - [1]={["y"]=366680.28571429,["x"]=11699.142857142,}, - [2]={["y"]=366654.28571429,["x"]=11225.142857142,}, - [3]={["y"]=367497.14285715,["x"]=11082.285714285,}, - [4]={["y"]=368025.71428572,["x"]=10396.57142857,}, - [5]={["y"]=369854.28571429,["x"]=11367.999999999,}, - [6]={["y"]=369840.00000001,["x"]=11910.857142856,}, - [7]={["y"]=366682.57142858,["x"]=11697.999999999,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=369205.42857144,["x"]=11789.142857142,}, - [2]={["y"]=369209.71428572,["x"]=11714.857142856,}, - [3]={["y"]=366699.71428572,["x"]=11581.714285713,}, - [4]={["y"]=366698.28571429,["x"]=11659.142857142,}, - [5]={["y"]=369208.85714286,["x"]=11788.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - KrasnodarPashkovsky = { - PointsBoundary = { - [1]={["y"]=386754,["x"]=6476.5714285703,}, - [2]={["y"]=389182.57142858,["x"]=8722.2857142846,}, - [3]={["y"]=388832.57142858,["x"]=9086.5714285703,}, - [4]={["y"]=386961.14285715,["x"]=7707.9999999989,}, - [5]={["y"]=385404,["x"]=9179.4285714274,}, - [6]={["y"]=383239.71428572,["x"]=7386.5714285703,}, - [7]={["y"]=383954,["x"]=6486.5714285703,}, - [8]={["y"]=385775.42857143,["x"]=8097.9999999989,}, - [9]={["y"]=386804,["x"]=7319.4285714274,}, - [10]={["y"]=386375.42857143,["x"]=6797.9999999989,}, - [11]={["y"]=386746.85714286,["x"]=6472.2857142846,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=385891.14285715,["x"]=8416.5714285703,}, - [2]={["y"]=385842.28571429,["x"]=8467.9999999989,}, - [3]={["y"]=384180.85714286,["x"]=6917.1428571417,}, - [4]={["y"]=384228.57142858,["x"]=6867.7142857132,}, - [5]={["y"]=385891.14285715,["x"]=8416.5714285703,}, - }, - [2] = { - [1]={["y"]=386714.85714286,["x"]=6674.857142856,}, - [2]={["y"]=386757.71428572,["x"]=6627.7142857132,}, - [3]={["y"]=389028.57142858,["x"]=8741.4285714275,}, - [4]={["y"]=388981.71428572,["x"]=8790.5714285703,}, - [5]={["y"]=386714.57142858,["x"]=6674.5714285703,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Krymsk = { - PointsBoundary = { - [1]={["y"]=293338.00000001,["x"]=-7575.4285714297,}, - [2]={["y"]=295199.42857144,["x"]=-5434.0000000011,}, - [3]={["y"]=295595.14285715,["x"]=-6239.7142857154,}, - [4]={["y"]=294152.2857143,["x"]=-8325.4285714297,}, - [5]={["y"]=293345.14285715,["x"]=-7596.8571428582,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=293522.00000001,["x"]=-7567.4285714297,}, - [2]={["y"]=293578.57142858,["x"]=-7616.0000000011,}, - [3]={["y"]=295246.00000001,["x"]=-5591.142857144,}, - [4]={["y"]=295187.71428573,["x"]=-5546.0000000011,}, - [5]={["y"]=293523.14285715,["x"]=-7568.2857142868,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Kutaisi = { - PointsBoundary = { - [1]={["y"]=682087.42857143,["x"]=-284512.85714286,}, - [2]={["y"]=685387.42857143,["x"]=-283662.85714286,}, - [3]={["y"]=685294.57142857,["x"]=-284977.14285715,}, - [4]={["y"]=682744.57142857,["x"]=-286505.71428572,}, - [5]={["y"]=682094.57142857,["x"]=-284527.14285715,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=682638,["x"]=-285202.28571429,}, - [2]={["y"]=685050.28571429,["x"]=-284507.42857144,}, - [3]={["y"]=685068.85714286,["x"]=-284578.85714286,}, - [4]={["y"]=682657.42857143,["x"]=-285264.28571429,}, - [5]={["y"]=682638.28571429,["x"]=-285202.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - MaykopKhanskaya = { - PointsBoundary = { - [1]={["y"]=456876.28571429,["x"]=-27665.42857143,}, - [2]={["y"]=457800,["x"]=-28392.857142858,}, - [3]={["y"]=459368.57142857,["x"]=-26378.571428573,}, - [4]={["y"]=459425.71428572,["x"]=-25242.857142858,}, - [5]={["y"]=458961.42857143,["x"]=-24964.285714287,}, - [6]={["y"]=456878.57142857,["x"]=-27667.714285715,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=457005.42857143,["x"]=-27668.000000001,}, - [2]={["y"]=459028.85714286,["x"]=-25168.857142858,}, - [3]={["y"]=459082.57142857,["x"]=-25216.857142858,}, - [4]={["y"]=457060,["x"]=-27714.285714287,}, - [5]={["y"]=457004.57142857,["x"]=-27669.714285715,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - MineralnyeVody = { - PointsBoundary = { - [1]={["y"]=703857.14285714,["x"]=-50226.000000002,}, - [2]={["y"]=707385.71428571,["x"]=-51911.714285716,}, - [3]={["y"]=707595.71428571,["x"]=-51434.857142859,}, - [4]={["y"]=707900,["x"]=-51568.857142859,}, - [5]={["y"]=707542.85714286,["x"]=-52326.000000002,}, - [6]={["y"]=706628.57142857,["x"]=-52568.857142859,}, - [7]={["y"]=705142.85714286,["x"]=-51790.285714288,}, - [8]={["y"]=703678.57142857,["x"]=-50611.714285716,}, - [9]={["y"]=703857.42857143,["x"]=-50226.857142859,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=703904,["x"]=-50352.571428573,}, - [2]={["y"]=707596.28571429,["x"]=-52094.571428573,}, - [3]={["y"]=707560.57142858,["x"]=-52161.714285716,}, - [4]={["y"]=703871.71428572,["x"]=-50420.571428573,}, - [5]={["y"]=703902,["x"]=-50352.000000002,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Mozdok = { - PointsBoundary = { - [1]={["y"]=832123.42857143,["x"]=-83608.571428573,}, - [2]={["y"]=835916.28571429,["x"]=-83144.285714288,}, - [3]={["y"]=835474.28571429,["x"]=-84170.571428573,}, - [4]={["y"]=832911.42857143,["x"]=-84470.571428573,}, - [5]={["y"]=832487.71428572,["x"]=-85565.714285716,}, - [6]={["y"]=831573.42857143,["x"]=-85351.42857143,}, - [7]={["y"]=832123.71428572,["x"]=-83610.285714288,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=832201.14285715,["x"]=-83699.428571431,}, - [2]={["y"]=832212.57142857,["x"]=-83780.571428574,}, - [3]={["y"]=835730.28571429,["x"]=-83335.714285717,}, - [4]={["y"]=835718.85714286,["x"]=-83246.571428574,}, - [5]={["y"]=832200.57142857,["x"]=-83700.000000002,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Nalchik = { - PointsBoundary = { - [1]={["y"]=759370,["x"]=-125502.85714286,}, - [2]={["y"]=761384.28571429,["x"]=-124177.14285714,}, - [3]={["y"]=761472.85714286,["x"]=-124325.71428572,}, - [4]={["y"]=761092.85714286,["x"]=-125048.57142857,}, - [5]={["y"]=760295.71428572,["x"]=-125685.71428572,}, - [6]={["y"]=759444.28571429,["x"]=-125734.28571429,}, - [7]={["y"]=759375.71428572,["x"]=-125511.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=759454.28571429,["x"]=-125551.42857143,}, - [2]={["y"]=759492.85714286,["x"]=-125610.85714286,}, - [3]={["y"]=761406.28571429,["x"]=-124304.28571429,}, - [4]={["y"]=761361.14285714,["x"]=-124239.71428572,}, - [5]={["y"]=759456,["x"]=-125552.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Novorossiysk = { - PointsBoundary = { - [1]={["y"]=278677.71428573,["x"]=-41656.571428572,}, - [2]={["y"]=278446.2857143,["x"]=-41453.714285715,}, - [3]={["y"]=278989.14285716,["x"]=-40188.000000001,}, - [4]={["y"]=279717.71428573,["x"]=-39968.000000001,}, - [5]={["y"]=280020.57142859,["x"]=-40208.000000001,}, - [6]={["y"]=278674.85714287,["x"]=-41660.857142858,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=278673.14285716,["x"]=-41615.142857144,}, - [2]={["y"]=278625.42857144,["x"]=-41570.571428572,}, - [3]={["y"]=279835.42857144,["x"]=-40226.000000001,}, - [4]={["y"]=279882.2857143,["x"]=-40270.000000001,}, - [5]={["y"]=278672.00000001,["x"]=-41614.857142858,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SenakiKolkhi = { - PointsBoundary = { - [1]={["y"]=646036.57142857,["x"]=-281778.85714286,}, - [2]={["y"]=646045.14285714,["x"]=-281191.71428571,}, - [3]={["y"]=647032.28571429,["x"]=-280598.85714285,}, - [4]={["y"]=647669.42857143,["x"]=-281273.14285714,}, - [5]={["y"]=648323.71428571,["x"]=-281370.28571428,}, - [6]={["y"]=648520.85714286,["x"]=-281978.85714285,}, - [7]={["y"]=646039.42857143,["x"]=-281783.14285714,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=646060.85714285,["x"]=-281736,}, - [2]={["y"]=646056.57142857,["x"]=-281631.71428571,}, - [3]={["y"]=648442.28571428,["x"]=-281840.28571428,}, - [4]={["y"]=648432.28571428,["x"]=-281918.85714286,}, - [5]={["y"]=646063.71428571,["x"]=-281738.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SochiAdler = { - PointsBoundary = { - [1]={["y"]=460642.28571428,["x"]=-164861.71428571,}, - [2]={["y"]=462820.85714285,["x"]=-163368.85714286,}, - [3]={["y"]=463649.42857142,["x"]=-163340.28571429,}, - [4]={["y"]=463835.14285714,["x"]=-164040.28571429,}, - [5]={["y"]=462535.14285714,["x"]=-165654.57142857,}, - [6]={["y"]=460678,["x"]=-165247.42857143,}, - [7]={["y"]=460635.14285714,["x"]=-164876,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=460831.42857143,["x"]=-165180,}, - [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, - [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, - [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, - [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, - }, - [2] = { - [1]={["y"]=460831.42857143,["x"]=-165180,}, - [2]={["y"]=460878.57142857,["x"]=-165257.14285714,}, - [3]={["y"]=463663.71428571,["x"]=-163793.14285714,}, - [4]={["y"]=463612.28571428,["x"]=-163697.42857143,}, - [5]={["y"]=460831.42857143,["x"]=-165177.14285714,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Soganlug = { - PointsBoundary = { - [1]={["y"]=894530.85714286,["x"]=-316928.28571428,}, - [2]={["y"]=896422.28571428,["x"]=-318622.57142857,}, - [3]={["y"]=896090.85714286,["x"]=-318934,}, - [4]={["y"]=894019.42857143,["x"]=-317119.71428571,}, - [5]={["y"]=894533.71428571,["x"]=-316925.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=894525.71428571,["x"]=-316964,}, - [2]={["y"]=896363.14285714,["x"]=-318634.28571428,}, - [3]={["y"]=896299.14285714,["x"]=-318702.85714286,}, - [4]={["y"]=894464,["x"]=-317031.71428571,}, - [5]={["y"]=894524.57142857,["x"]=-316963.71428571,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - SukhumiBabushara = { - PointsBoundary = { - [1]={["y"]=562541.14285714,["x"]=-219852.28571429,}, - [2]={["y"]=562691.14285714,["x"]=-219395.14285714,}, - [3]={["y"]=564326.85714286,["x"]=-219523.71428571,}, - [4]={["y"]=566262.57142857,["x"]=-221166.57142857,}, - [5]={["y"]=566069.71428571,["x"]=-221580.85714286,}, - [6]={["y"]=562534,["x"]=-219873.71428571,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=562684,["x"]=-219779.71428571,}, - [2]={["y"]=562717.71428571,["x"]=-219718,}, - [3]={["y"]=566046.85714286,["x"]=-221376.57142857,}, - [4]={["y"]=566012.28571428,["x"]=-221446.57142857,}, - [5]={["y"]=562684.57142857,["x"]=-219782.57142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - TbilisiLochini = { - PointsBoundary = { - [1]={["y"]=895172.85714286,["x"]=-314667.42857143,}, - [2]={["y"]=895337.42857143,["x"]=-314143.14285714,}, - [3]={["y"]=895990.28571429,["x"]=-314036,}, - [4]={["y"]=897730.28571429,["x"]=-315284.57142857,}, - [5]={["y"]=897901.71428571,["x"]=-316284.57142857,}, - [6]={["y"]=897684.57142857,["x"]=-316618.85714286,}, - [7]={["y"]=895173.14285714,["x"]=-314667.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=895261.14285715,["x"]=-314652.28571428,}, - [2]={["y"]=897654.57142857,["x"]=-316523.14285714,}, - [3]={["y"]=897711.71428571,["x"]=-316450.28571429,}, - [4]={["y"]=895327.42857143,["x"]=-314568.85714286,}, - [5]={["y"]=895261.71428572,["x"]=-314656,}, - }, - [2] = { - [1]={["y"]=895605.71428572,["x"]=-314724.57142857,}, - [2]={["y"]=897639.71428572,["x"]=-316148,}, - [3]={["y"]=897683.42857143,["x"]=-316087.14285714,}, - [4]={["y"]=895650,["x"]=-314660,}, - [5]={["y"]=895606,["x"]=-314724.85714286,} - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Vaziani = { - PointsBoundary = { - [1]={["y"]=902122,["x"]=-318163.71428572,}, - [2]={["y"]=902678.57142857,["x"]=-317594,}, - [3]={["y"]=903275.71428571,["x"]=-317405.42857143,}, - [4]={["y"]=903418.57142857,["x"]=-317891.14285714,}, - [5]={["y"]=904292.85714286,["x"]=-318748.28571429,}, - [6]={["y"]=904542,["x"]=-319740.85714286,}, - [7]={["y"]=904042,["x"]=-320166.57142857,}, - [8]={["y"]=902121.42857143,["x"]=-318164.85714286,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=902239.14285714,["x"]=-318190.85714286,}, - [2]={["y"]=904014.28571428,["x"]=-319994.57142857,}, - [3]={["y"]=904064.85714285,["x"]=-319945.14285715,}, - [4]={["y"]=902294.57142857,["x"]=-318146,}, - [5]={["y"]=902247.71428571,["x"]=-318190.85714286,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - }, -} - ---- Creates a new AIRBASEPOLICE_CAUCASUS object. --- @param #AIRBASEPOLICE_CAUCASUS self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @return #AIRBASEPOLICE_CAUCASUS self -function AIRBASEPOLICE_CAUCASUS:New( SetClient ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) - - -- -- AnapaVityazevo - -- local AnapaVityazevoBoundary = GROUP:FindByName( "AnapaVityazevo Boundary" ) - -- self.Airbases.AnapaVityazevo.ZoneBoundary = ZONE_POLYGON:New( "AnapaVityazevo Boundary", AnapaVityazevoBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local AnapaVityazevoRunway1 = GROUP:FindByName( "AnapaVityazevo Runway 1" ) - -- self.Airbases.AnapaVityazevo.ZoneRunways[1] = ZONE_POLYGON:New( "AnapaVityazevo Runway 1", AnapaVityazevoRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Batumi - -- local BatumiBoundary = GROUP:FindByName( "Batumi Boundary" ) - -- self.Airbases.Batumi.ZoneBoundary = ZONE_POLYGON:New( "Batumi Boundary", BatumiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local BatumiRunway1 = GROUP:FindByName( "Batumi Runway 1" ) - -- self.Airbases.Batumi.ZoneRunways[1] = ZONE_POLYGON:New( "Batumi Runway 1", BatumiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Beslan - -- local BeslanBoundary = GROUP:FindByName( "Beslan Boundary" ) - -- self.Airbases.Beslan.ZoneBoundary = ZONE_POLYGON:New( "Beslan Boundary", BeslanBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local BeslanRunway1 = GROUP:FindByName( "Beslan Runway 1" ) - -- self.Airbases.Beslan.ZoneRunways[1] = ZONE_POLYGON:New( "Beslan Runway 1", BeslanRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Gelendzhik - -- local GelendzhikBoundary = GROUP:FindByName( "Gelendzhik Boundary" ) - -- self.Airbases.Gelendzhik.ZoneBoundary = ZONE_POLYGON:New( "Gelendzhik Boundary", GelendzhikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local GelendzhikRunway1 = GROUP:FindByName( "Gelendzhik Runway 1" ) - -- self.Airbases.Gelendzhik.ZoneRunways[1] = ZONE_POLYGON:New( "Gelendzhik Runway 1", GelendzhikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Gudauta - -- local GudautaBoundary = GROUP:FindByName( "Gudauta Boundary" ) - -- self.Airbases.Gudauta.ZoneBoundary = ZONE_POLYGON:New( "Gudauta Boundary", GudautaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local GudautaRunway1 = GROUP:FindByName( "Gudauta Runway 1" ) - -- self.Airbases.Gudauta.ZoneRunways[1] = ZONE_POLYGON:New( "Gudauta Runway 1", GudautaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Kobuleti - -- local KobuletiBoundary = GROUP:FindByName( "Kobuleti Boundary" ) - -- self.Airbases.Kobuleti.ZoneBoundary = ZONE_POLYGON:New( "Kobuleti Boundary", KobuletiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KobuletiRunway1 = GROUP:FindByName( "Kobuleti Runway 1" ) - -- self.Airbases.Kobuleti.ZoneRunways[1] = ZONE_POLYGON:New( "Kobuleti Runway 1", KobuletiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- KrasnodarCenter - -- local KrasnodarCenterBoundary = GROUP:FindByName( "KrasnodarCenter Boundary" ) - -- self.Airbases.KrasnodarCenter.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarCenter Boundary", KrasnodarCenterBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrasnodarCenterRunway1 = GROUP:FindByName( "KrasnodarCenter Runway 1" ) - -- self.Airbases.KrasnodarCenter.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarCenter Runway 1", KrasnodarCenterRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- KrasnodarPashkovsky - -- local KrasnodarPashkovskyBoundary = GROUP:FindByName( "KrasnodarPashkovsky Boundary" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarPashkovsky Boundary", KrasnodarPashkovskyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrasnodarPashkovskyRunway1 = GROUP:FindByName( "KrasnodarPashkovsky Runway 1" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 1", KrasnodarPashkovskyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- local KrasnodarPashkovskyRunway2 = GROUP:FindByName( "KrasnodarPashkovsky Runway 2" ) - -- self.Airbases.KrasnodarPashkovsky.ZoneRunways[2] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 2", KrasnodarPashkovskyRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Krymsk - -- local KrymskBoundary = GROUP:FindByName( "Krymsk Boundary" ) - -- self.Airbases.Krymsk.ZoneBoundary = ZONE_POLYGON:New( "Krymsk Boundary", KrymskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KrymskRunway1 = GROUP:FindByName( "Krymsk Runway 1" ) - -- self.Airbases.Krymsk.ZoneRunways[1] = ZONE_POLYGON:New( "Krymsk Runway 1", KrymskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Kutaisi - -- local KutaisiBoundary = GROUP:FindByName( "Kutaisi Boundary" ) - -- self.Airbases.Kutaisi.ZoneBoundary = ZONE_POLYGON:New( "Kutaisi Boundary", KutaisiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local KutaisiRunway1 = GROUP:FindByName( "Kutaisi Runway 1" ) - -- self.Airbases.Kutaisi.ZoneRunways[1] = ZONE_POLYGON:New( "Kutaisi Runway 1", KutaisiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- MaykopKhanskaya - -- local MaykopKhanskayaBoundary = GROUP:FindByName( "MaykopKhanskaya Boundary" ) - -- self.Airbases.MaykopKhanskaya.ZoneBoundary = ZONE_POLYGON:New( "MaykopKhanskaya Boundary", MaykopKhanskayaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MaykopKhanskayaRunway1 = GROUP:FindByName( "MaykopKhanskaya Runway 1" ) - -- self.Airbases.MaykopKhanskaya.ZoneRunways[1] = ZONE_POLYGON:New( "MaykopKhanskaya Runway 1", MaykopKhanskayaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- MineralnyeVody - -- local MineralnyeVodyBoundary = GROUP:FindByName( "MineralnyeVody Boundary" ) - -- self.Airbases.MineralnyeVody.ZoneBoundary = ZONE_POLYGON:New( "MineralnyeVody Boundary", MineralnyeVodyBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MineralnyeVodyRunway1 = GROUP:FindByName( "MineralnyeVody Runway 1" ) - -- self.Airbases.MineralnyeVody.ZoneRunways[1] = ZONE_POLYGON:New( "MineralnyeVody Runway 1", MineralnyeVodyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Mozdok - -- local MozdokBoundary = GROUP:FindByName( "Mozdok Boundary" ) - -- self.Airbases.Mozdok.ZoneBoundary = ZONE_POLYGON:New( "Mozdok Boundary", MozdokBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local MozdokRunway1 = GROUP:FindByName( "Mozdok Runway 1" ) - -- self.Airbases.Mozdok.ZoneRunways[1] = ZONE_POLYGON:New( "Mozdok Runway 1", MozdokRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Nalchik - -- local NalchikBoundary = GROUP:FindByName( "Nalchik Boundary" ) - -- self.Airbases.Nalchik.ZoneBoundary = ZONE_POLYGON:New( "Nalchik Boundary", NalchikBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local NalchikRunway1 = GROUP:FindByName( "Nalchik Runway 1" ) - -- self.Airbases.Nalchik.ZoneRunways[1] = ZONE_POLYGON:New( "Nalchik Runway 1", NalchikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Novorossiysk - -- local NovorossiyskBoundary = GROUP:FindByName( "Novorossiysk Boundary" ) - -- self.Airbases.Novorossiysk.ZoneBoundary = ZONE_POLYGON:New( "Novorossiysk Boundary", NovorossiyskBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local NovorossiyskRunway1 = GROUP:FindByName( "Novorossiysk Runway 1" ) - -- self.Airbases.Novorossiysk.ZoneRunways[1] = ZONE_POLYGON:New( "Novorossiysk Runway 1", NovorossiyskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SenakiKolkhi - -- local SenakiKolkhiBoundary = GROUP:FindByName( "SenakiKolkhi Boundary" ) - -- self.Airbases.SenakiKolkhi.ZoneBoundary = ZONE_POLYGON:New( "SenakiKolkhi Boundary", SenakiKolkhiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SenakiKolkhiRunway1 = GROUP:FindByName( "SenakiKolkhi Runway 1" ) - -- self.Airbases.SenakiKolkhi.ZoneRunways[1] = ZONE_POLYGON:New( "SenakiKolkhi Runway 1", SenakiKolkhiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SochiAdler - -- local SochiAdlerBoundary = GROUP:FindByName( "SochiAdler Boundary" ) - -- self.Airbases.SochiAdler.ZoneBoundary = ZONE_POLYGON:New( "SochiAdler Boundary", SochiAdlerBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SochiAdlerRunway1 = GROUP:FindByName( "SochiAdler Runway 1" ) - -- self.Airbases.SochiAdler.ZoneRunways[1] = ZONE_POLYGON:New( "SochiAdler Runway 1", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- local SochiAdlerRunway2 = GROUP:FindByName( "SochiAdler Runway 2" ) - -- self.Airbases.SochiAdler.ZoneRunways[2] = ZONE_POLYGON:New( "SochiAdler Runway 2", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Soganlug - -- local SoganlugBoundary = GROUP:FindByName( "Soganlug Boundary" ) - -- self.Airbases.Soganlug.ZoneBoundary = ZONE_POLYGON:New( "Soganlug Boundary", SoganlugBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SoganlugRunway1 = GROUP:FindByName( "Soganlug Runway 1" ) - -- self.Airbases.Soganlug.ZoneRunways[1] = ZONE_POLYGON:New( "Soganlug Runway 1", SoganlugRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- SukhumiBabushara - -- local SukhumiBabusharaBoundary = GROUP:FindByName( "SukhumiBabushara Boundary" ) - -- self.Airbases.SukhumiBabushara.ZoneBoundary = ZONE_POLYGON:New( "SukhumiBabushara Boundary", SukhumiBabusharaBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local SukhumiBabusharaRunway1 = GROUP:FindByName( "SukhumiBabushara Runway 1" ) - -- self.Airbases.SukhumiBabushara.ZoneRunways[1] = ZONE_POLYGON:New( "SukhumiBabushara Runway 1", SukhumiBabusharaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- TbilisiLochini - -- local TbilisiLochiniBoundary = GROUP:FindByName( "TbilisiLochini Boundary" ) - -- self.Airbases.TbilisiLochini.ZoneBoundary = ZONE_POLYGON:New( "TbilisiLochini Boundary", TbilisiLochiniBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local TbilisiLochiniRunway1 = GROUP:FindByName( "TbilisiLochini Runway 1" ) - -- self.Airbases.TbilisiLochini.ZoneRunways[1] = ZONE_POLYGON:New( "TbilisiLochini Runway 1", TbilisiLochiniRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- local TbilisiLochiniRunway2 = GROUP:FindByName( "TbilisiLochini Runway 2" ) - -- self.Airbases.TbilisiLochini.ZoneRunways[2] = ZONE_POLYGON:New( "TbilisiLochini Runway 2", TbilisiLochiniRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - -- -- Vaziani - -- local VazianiBoundary = GROUP:FindByName( "Vaziani Boundary" ) - -- self.Airbases.Vaziani.ZoneBoundary = ZONE_POLYGON:New( "Vaziani Boundary", VazianiBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local VazianiRunway1 = GROUP:FindByName( "Vaziani Runway 1" ) - -- self.Airbases.Vaziani.ZoneRunways[1] = ZONE_POLYGON:New( "Vaziani Runway 1", VazianiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - -- - -- - -- - - - -- Template - -- local TemplateBoundary = GROUP:FindByName( "Template Boundary" ) - -- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush() - -- - -- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" ) - -- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() - - return self - -end - - - - ---- @type AIRBASEPOLICE_NEVADA --- @extends Functional.AirbasePolice#AIRBASEPOLICE_BASE -AIRBASEPOLICE_NEVADA = { - ClassName = "AIRBASEPOLICE_NEVADA", - Airbases = { - Nellis = { - PointsBoundary = { - [1]={["y"]=-17814.714285714,["x"]=-399823.14285714,}, - [2]={["y"]=-16875.857142857,["x"]=-398763.14285714,}, - [3]={["y"]=-16251.571428571,["x"]=-398988.85714286,}, - [4]={["y"]=-16163,["x"]=-398693.14285714,}, - [5]={["y"]=-16328.714285714,["x"]=-398034.57142857,}, - [6]={["y"]=-15943,["x"]=-397571.71428571,}, - [7]={["y"]=-15711.571428571,["x"]=-397551.71428571,}, - [8]={["y"]=-15748.714285714,["x"]=-396806,}, - [9]={["y"]=-16288.714285714,["x"]=-396517.42857143,}, - [10]={["y"]=-16751.571428571,["x"]=-396308.85714286,}, - [11]={["y"]=-17263,["x"]=-396234.57142857,}, - [12]={["y"]=-17577.285714286,["x"]=-396640.28571429,}, - [13]={["y"]=-17614.428571429,["x"]=-397400.28571429,}, - [14]={["y"]=-19405.857142857,["x"]=-399428.85714286,}, - [15]={["y"]=-19234.428571429,["x"]=-399683.14285714,}, - [16]={["y"]=-18708.714285714,["x"]=-399408.85714286,}, - [17]={["y"]=-18397.285714286,["x"]=-399657.42857143,}, - [18]={["y"]=-17814.428571429,["x"]=-399823.42857143,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-18687,["x"]=-399380.28571429,}, - [2]={["y"]=-18620.714285714,["x"]=-399436.85714286,}, - [3]={["y"]=-16217.857142857,["x"]=-396596.85714286,}, - [4]={["y"]=-16300.142857143,["x"]=-396530,}, - [5]={["y"]=-18687,["x"]=-399380.85714286,}, - }, - [2] = { - [1]={["y"]=-18451.571428572,["x"]=-399580.57142857,}, - [2]={["y"]=-18392.142857143,["x"]=-399628.57142857,}, - [3]={["y"]=-16011,["x"]=-396806.85714286,}, - [4]={["y"]=-16074.714285714,["x"]=-396751.71428572,}, - [5]={["y"]=-18451.571428572,["x"]=-399580.85714285,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - McCarran = { - PointsBoundary = { - [1]={["y"]=-29455.285714286,["x"]=-416277.42857142,}, - [2]={["y"]=-28860.142857143,["x"]=-416492,}, - [3]={["y"]=-25044.428571429,["x"]=-416344.85714285,}, - [4]={["y"]=-24580.142857143,["x"]=-415959.14285714,}, - [5]={["y"]=-25073,["x"]=-415630.57142857,}, - [6]={["y"]=-25087.285714286,["x"]=-415130.57142857,}, - [7]={["y"]=-25830.142857143,["x"]=-414866.28571428,}, - [8]={["y"]=-26658.714285715,["x"]=-414880.57142857,}, - [9]={["y"]=-26973,["x"]=-415273.42857142,}, - [10]={["y"]=-27380.142857143,["x"]=-415187.71428571,}, - [11]={["y"]=-27715.857142857,["x"]=-414144.85714285,}, - [12]={["y"]=-27551.571428572,["x"]=-413473.42857142,}, - [13]={["y"]=-28630.142857143,["x"]=-413201.99999999,}, - [14]={["y"]=-29494.428571429,["x"]=-415437.71428571,}, - [15]={["y"]=-29455.571428572,["x"]=-416277.71428571,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-29408.428571429,["x"]=-416016.28571428,}, - [2]={["y"]=-29408.142857144,["x"]=-416105.42857142,}, - [3]={["y"]=-24680.714285715,["x"]=-416003.14285713,}, - [4]={["y"]=-24681.857142858,["x"]=-415926.57142856,}, - [5]={["y"]=-29408.42857143,["x"]=-416016.57142856,}, - }, - [2] = { - [1]={["y"]=-28575.571428572,["x"]=-416303.14285713,}, - [2]={["y"]=-28575.571428572,["x"]=-416382.57142856,}, - [3]={["y"]=-25111.000000001,["x"]=-416309.7142857,}, - [4]={["y"]=-25111.000000001,["x"]=-416249.14285713,}, - [5]={["y"]=-28575.571428572,["x"]=-416303.7142857,}, - }, - [3] = { - [1]={["y"]=-29331.000000001,["x"]=-416275.42857141,}, - [2]={["y"]=-29259.000000001,["x"]=-416306.85714284,}, - [3]={["y"]=-28005.571428572,["x"]=-413449.7142857,}, - [4]={["y"]=-28068.714285715,["x"]=-413422.85714284,}, - [5]={["y"]=-29331.000000001,["x"]=-416275.7142857,}, - }, - [4] = { - [1]={["y"]=-29073.285714286,["x"]=-416386.57142856,}, - [2]={["y"]=-28997.285714286,["x"]=-416417.42857141,}, - [3]={["y"]=-27697.571428572,["x"]=-413464.57142856,}, - [4]={["y"]=-27767.857142858,["x"]=-413434.28571427,}, - [5]={["y"]=-29073.000000001,["x"]=-416386.85714284,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - Creech = { - PointsBoundary = { - [1]={["y"]=-74522.714285715,["x"]=-360887.99999998,}, - [2]={["y"]=-74197,["x"]=-360556.57142855,}, - [3]={["y"]=-74402.714285715,["x"]=-359639.42857141,}, - [4]={["y"]=-74637,["x"]=-359279.42857141,}, - [5]={["y"]=-75759.857142857,["x"]=-359005.14285712,}, - [6]={["y"]=-75834.142857143,["x"]=-359045.14285712,}, - [7]={["y"]=-75902.714285714,["x"]=-359782.28571427,}, - [8]={["y"]=-76099.857142857,["x"]=-360399.42857141,}, - [9]={["y"]=-77314.142857143,["x"]=-360219.42857141,}, - [10]={["y"]=-77728.428571429,["x"]=-360445.14285713,}, - [11]={["y"]=-77585.571428571,["x"]=-360585.14285713,}, - [12]={["y"]=-76471.285714286,["x"]=-360819.42857141,}, - [13]={["y"]=-76325.571428571,["x"]=-360942.28571427,}, - [14]={["y"]=-74671.857142857,["x"]=-360927.7142857,}, - [15]={["y"]=-74522.714285714,["x"]=-360888.85714284,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-74237.571428571,["x"]=-360591.7142857,}, - [2]={["y"]=-74234.428571429,["x"]=-360493.71428571,}, - [3]={["y"]=-77605.285714286,["x"]=-360399.14285713,}, - [4]={["y"]=-77608.714285715,["x"]=-360498.85714285,}, - [5]={["y"]=-74237.857142857,["x"]=-360591.7142857,}, - }, - [2] = { - [1]={["y"]=-75807.571428572,["x"]=-359073.42857142,}, - [2]={["y"]=-74770.142857144,["x"]=-360581.71428571,}, - [3]={["y"]=-74641.285714287,["x"]=-360585.42857142,}, - [4]={["y"]=-75734.142857144,["x"]=-359023.14285714,}, - [5]={["y"]=-75807.285714287,["x"]=-359073.42857142,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - GroomLake = { - PointsBoundary = { - [1]={["y"]=-88916.714285714,["x"]=-289102.28571425,}, - [2]={["y"]=-87023.571428572,["x"]=-290388.57142857,}, - [3]={["y"]=-85916.428571429,["x"]=-290674.28571428,}, - [4]={["y"]=-87645.000000001,["x"]=-286567.14285714,}, - [5]={["y"]=-88380.714285715,["x"]=-286388.57142857,}, - [6]={["y"]=-89670.714285715,["x"]=-283524.28571428,}, - [7]={["y"]=-89797.857142858,["x"]=-283567.14285714,}, - [8]={["y"]=-88635.000000001,["x"]=-286749.99999999,}, - [9]={["y"]=-89177.857142858,["x"]=-287207.14285714,}, - [10]={["y"]=-89092.142857144,["x"]=-288892.85714285,}, - [11]={["y"]=-88917.000000001,["x"]=-289102.85714285,}, - }, - PointsRunways = { - [1] = { - [1]={["y"]=-86039.000000001,["x"]=-290606.28571428,}, - [2]={["y"]=-85965.285714287,["x"]=-290573.99999999,}, - [3]={["y"]=-87692.714285715,["x"]=-286634.85714285,}, - [4]={["y"]=-87756.714285715,["x"]=-286663.99999999,}, - [5]={["y"]=-86038.714285715,["x"]=-290606.85714285,}, - }, - [2] = { - [1]={["y"]=-86808.428571429,["x"]=-290375.7142857,}, - [2]={["y"]=-86732.714285715,["x"]=-290344.28571427,}, - [3]={["y"]=-89672.714285714,["x"]=-283546.57142855,}, - [4]={["y"]=-89772.142857143,["x"]=-283587.71428569,}, - [5]={["y"]=-86808.142857143,["x"]=-290375.7142857,}, - }, - }, - ZoneBoundary = {}, - ZoneRunways = {}, - MaximumSpeed = 50, - }, - }, -} - ---- Creates a new AIRBASEPOLICE_NEVADA object. --- @param #AIRBASEPOLICE_NEVADA self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase. --- @return #AIRBASEPOLICE_NEVADA self -function AIRBASEPOLICE_NEVADA:New( SetClient ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AIRBASEPOLICE_BASE:New( SetClient, self.Airbases ) ) - --- -- Nellis --- local NellisBoundary = GROUP:FindByName( "Nellis Boundary" ) --- self.Airbases.Nellis.ZoneBoundary = ZONE_POLYGON:New( "Nellis Boundary", NellisBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local NellisRunway1 = GROUP:FindByName( "Nellis Runway 1" ) --- self.Airbases.Nellis.ZoneRunways[1] = ZONE_POLYGON:New( "Nellis Runway 1", NellisRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local NellisRunway2 = GROUP:FindByName( "Nellis Runway 2" ) --- self.Airbases.Nellis.ZoneRunways[2] = ZONE_POLYGON:New( "Nellis Runway 2", NellisRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- McCarran --- local McCarranBoundary = GROUP:FindByName( "McCarran Boundary" ) --- self.Airbases.McCarran.ZoneBoundary = ZONE_POLYGON:New( "McCarran Boundary", McCarranBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local McCarranRunway1 = GROUP:FindByName( "McCarran Runway 1" ) --- self.Airbases.McCarran.ZoneRunways[1] = ZONE_POLYGON:New( "McCarran Runway 1", McCarranRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway2 = GROUP:FindByName( "McCarran Runway 2" ) --- self.Airbases.McCarran.ZoneRunways[2] = ZONE_POLYGON:New( "McCarran Runway 2", McCarranRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway3 = GROUP:FindByName( "McCarran Runway 3" ) --- self.Airbases.McCarran.ZoneRunways[3] = ZONE_POLYGON:New( "McCarran Runway 3", McCarranRunway3 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local McCarranRunway4 = GROUP:FindByName( "McCarran Runway 4" ) --- self.Airbases.McCarran.ZoneRunways[4] = ZONE_POLYGON:New( "McCarran Runway 4", McCarranRunway4 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- Creech --- local CreechBoundary = GROUP:FindByName( "Creech Boundary" ) --- self.Airbases.Creech.ZoneBoundary = ZONE_POLYGON:New( "Creech Boundary", CreechBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local CreechRunway1 = GROUP:FindByName( "Creech Runway 1" ) --- self.Airbases.Creech.ZoneRunways[1] = ZONE_POLYGON:New( "Creech Runway 1", CreechRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local CreechRunway2 = GROUP:FindByName( "Creech Runway 2" ) --- self.Airbases.Creech.ZoneRunways[2] = ZONE_POLYGON:New( "Creech Runway 2", CreechRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- -- Groom Lake --- local GroomLakeBoundary = GROUP:FindByName( "GroomLake Boundary" ) --- self.Airbases.GroomLake.ZoneBoundary = ZONE_POLYGON:New( "GroomLake Boundary", GroomLakeBoundary ):SmokeZone(SMOKECOLOR.White):Flush() --- --- local GroomLakeRunway1 = GROUP:FindByName( "GroomLake Runway 1" ) --- self.Airbases.GroomLake.ZoneRunways[1] = ZONE_POLYGON:New( "GroomLake Runway 1", GroomLakeRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush() --- --- local GroomLakeRunway2 = GROUP:FindByName( "GroomLake Runway 2" ) --- self.Airbases.GroomLake.ZoneRunways[2] = ZONE_POLYGON:New( "GroomLake Runway 2", GroomLakeRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush() - -end - - - - - - --- This module contains the DETECTION classes. --- --- === --- --- 1) @{Functional.Detection#DETECTION_BASE} class, extends @{Core.Base#BASE} --- ========================================================== --- The @{Functional.Detection#DETECTION_BASE} class defines the core functions to administer detected objects. --- The @{Functional.Detection#DETECTION_BASE} class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s). --- --- 1.1) DETECTION_BASE constructor --- ------------------------------- --- Construct a new DETECTION_BASE instance using the @{Functional.Detection#DETECTION_BASE.New}() method. --- --- 1.2) DETECTION_BASE initialization --- ---------------------------------- --- By default, detection will return detected objects with all the detection sensors available. --- However, you can ask how the objects were found with specific detection methods. --- If you use one of the below methods, the detection will work with the detection method specified. --- You can specify to apply multiple detection methods. --- --- Use the following functions to report the objects it detected using the methods Visual, Optical, Radar, IRST, RWR, DLINK: --- --- * @{Functional.Detection#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. --- * @{Functional.Detection#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. --- * @{Functional.Detection#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. --- * @{Functional.Detection#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. --- * @{Functional.Detection#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. --- * @{Functional.Detection#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. --- --- 1.3) Obtain objects detected by DETECTION_BASE --- ---------------------------------------------- --- DETECTION_BASE builds @{Set}s of objects detected. These @{Core.Set#SET_BASE}s can be retrieved using the method @{Functional.Detection#DETECTION_BASE.GetDetectedSets}(). --- The method will return a list (table) of @{Core.Set#SET_BASE} objects. --- --- === --- --- 2) @{Functional.Detection#DETECTION_AREAS} class, extends @{Functional.Detection#DETECTION_BASE} --- =============================================================================== --- The @{Functional.Detection#DETECTION_AREAS} class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s), --- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Wrapper.Unit#UNIT}s detected. --- The class is group the detected units within zones given a DetectedZoneRange parameter. --- A set with multiple detected zones will be created as there are groups of units detected. --- --- 2.1) Retrieve the Detected Unit sets and Detected Zones --- ------------------------------------------------------- --- The DetectedUnitSets methods are implemented in @{Functional.Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Functional.Detection#DETECTION_AREAS}. --- --- Retrieve the DetectedUnitSets with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Core.Set#SET_UNIT}s. --- To understand the amount of sets created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectedSetCount}(). --- If you want to obtain a specific set from the DetectedSets, use the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}() with a given index. --- --- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}(). --- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}(). --- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index. --- --- 1.4) Flare or Smoke detected units --- ---------------------------------- --- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place. --- --- 1.5) Flare or Smoke detected zones --- ---------------------------------- --- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedZones}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place. --- --- === --- --- ### Contributions: --- --- * Mechanist : Concept & Testing --- --- ### Authors: --- --- * FlightControl : Design & Programming --- --- @module Detection - - - ---- DETECTION_BASE class --- @type DETECTION_BASE --- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @field Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects. --- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified. --- @field #number DetectionRun --- @extends Core.Base#BASE -DETECTION_BASE = { - ClassName = "DETECTION_BASE", - DetectionSetGroup = nil, - DetectionRange = nil, - DetectedObjects = {}, - DetectionRun = 0, - DetectedObjectsIdentified = {}, -} - ---- @type DETECTION_BASE.DetectedObjects --- @list <#DETECTION_BASE.DetectedObject> - ---- @type DETECTION_BASE.DetectedObject --- @field #string Name --- @field #boolean Visible --- @field #string Type --- @field #number Distance --- @field #boolean Identified - ---- DETECTION constructor. --- @param #DETECTION_BASE self --- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @param Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @return #DETECTION_BASE self -function DETECTION_BASE:New( DetectionSetGroup, DetectionRange ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - self.DetectionSetGroup = DetectionSetGroup - self.DetectionRange = DetectionRange - - self:InitDetectVisual( false ) - self:InitDetectOptical( false ) - self:InitDetectRadar( false ) - self:InitDetectRWR( false ) - self:InitDetectIRST( false ) - self:InitDetectDLINK( false ) - - return self -end - ---- Detect Visual. --- @param #DETECTION_BASE self --- @param #boolean DetectVisual --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectVisual( DetectVisual ) - - self.DetectVisual = DetectVisual -end - ---- Detect Optical. --- @param #DETECTION_BASE self --- @param #boolean DetectOptical --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectOptical( DetectOptical ) - self:F2() - - self.DetectOptical = DetectOptical -end - ---- Detect Radar. --- @param #DETECTION_BASE self --- @param #boolean DetectRadar --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectRadar( DetectRadar ) - self:F2() - - self.DetectRadar = DetectRadar -end - ---- Detect IRST. --- @param #DETECTION_BASE self --- @param #boolean DetectIRST --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectIRST( DetectIRST ) - self:F2() - - self.DetectIRST = DetectIRST -end - ---- Detect RWR. --- @param #DETECTION_BASE self --- @param #boolean DetectRWR --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectRWR( DetectRWR ) - self:F2() - - self.DetectRWR = DetectRWR -end - ---- Detect DLINK. --- @param #DETECTION_BASE self --- @param #boolean DetectDLINK --- @return #DETECTION_BASE self -function DETECTION_BASE:InitDetectDLINK( DetectDLINK ) - self:F2() - - self.DetectDLINK = DetectDLINK -end - ---- Determines if a detected object has already been identified during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject --- @return #boolean true if already identified. -function DETECTION_BASE:IsDetectedObjectIdentified( DetectedObject ) - self:F3( DetectedObject.Name ) - - local DetectedObjectName = DetectedObject.Name - local DetectedObjectIdentified = self.DetectedObjectsIdentified[DetectedObjectName] == true - self:T3( DetectedObjectIdentified ) - return DetectedObjectIdentified -end - ---- Identifies a detected object during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject -function DETECTION_BASE:IdentifyDetectedObject( DetectedObject ) - self:F( DetectedObject.Name ) - - local DetectedObjectName = DetectedObject.Name - self.DetectedObjectsIdentified[DetectedObjectName] = true -end - ---- UnIdentify a detected object during detection processing. --- @param #DETECTION_BASE self --- @param #DETECTION_BASE.DetectedObject DetectedObject -function DETECTION_BASE:UnIdentifyDetectedObject( DetectedObject ) - - local DetectedObjectName = DetectedObject.Name - self.DetectedObjectsIdentified[DetectedObjectName] = false -end - ---- UnIdentify all detected objects during detection processing. --- @param #DETECTION_BASE self -function DETECTION_BASE:UnIdentifyAllDetectedObjects() - - self.DetectedObjectsIdentified = {} -- Table will be garbage collected. -end - ---- Gets a detected object with a given name. --- @param #DETECTION_BASE self --- @param #string ObjectName --- @return #DETECTION_BASE.DetectedObject -function DETECTION_BASE:GetDetectedObject( ObjectName ) - self:F3( ObjectName ) - - if ObjectName then - local DetectedObject = self.DetectedObjects[ObjectName] - - -- Only return detected objects that are alive! - local DetectedUnit = UNIT:FindByName( ObjectName ) - if DetectedUnit and DetectedUnit:IsAlive() then - if self:IsDetectedObjectIdentified( DetectedObject ) == false then - return DetectedObject - end - end - end - - return nil -end - ---- Get the detected @{Core.Set#SET_BASE}s. --- @param #DETECTION_BASE self --- @return #DETECTION_BASE.DetectedSets DetectedSets -function DETECTION_BASE:GetDetectedSets() - - local DetectionSets = self.DetectedSets - return DetectionSets -end - ---- Get the amount of SETs with detected objects. --- @param #DETECTION_BASE self --- @return #number Count -function DETECTION_BASE:GetDetectedSetCount() - - local DetectionSetCount = #self.DetectedSets - return DetectionSetCount -end - ---- Get a SET of detected objects using a given numeric index. --- @param #DETECTION_BASE self --- @param #number Index --- @return Core.Set#SET_BASE -function DETECTION_BASE:GetDetectedSet( Index ) - - local DetectionSet = self.DetectedSets[Index] - if DetectionSet then - return DetectionSet - end - - return nil -end - ---- Get the detection Groups. --- @param #DETECTION_BASE self --- @return Wrapper.Group#GROUP -function DETECTION_BASE:GetDetectionSetGroup() - - local DetectionSetGroup = self.DetectionSetGroup - return DetectionSetGroup -end - ---- Make a DetectionSet table. This function will be overridden in the derived clsses. --- @param #DETECTION_BASE self --- @return #DETECTION_BASE self -function DETECTION_BASE:CreateDetectionSets() - self:F2() - - self:E( "Error, in DETECTION_BASE class..." ) - -end - - ---- Schedule the DETECTION construction. --- @param #DETECTION_BASE self --- @param #number DelayTime The delay in seconds to wait the reporting. --- @param #number RepeatInterval The repeat interval in seconds for the reporting to happen repeatedly. --- @return #DETECTION_BASE self -function DETECTION_BASE:Schedule( DelayTime, RepeatInterval ) - self:F2() - - self.ScheduleDelayTime = DelayTime - self.ScheduleRepeatInterval = RepeatInterval - - self.DetectionScheduler = SCHEDULER:New(self, self._DetectionScheduler, { self, "Detection" }, DelayTime, RepeatInterval ) - return self -end - - ---- Form @{Set}s of detected @{Wrapper.Unit#UNIT}s in an array of @{Core.Set#SET_BASE}s. --- @param #DETECTION_BASE self -function DETECTION_BASE:_DetectionScheduler( SchedulerName ) - self:F2( { SchedulerName } ) - - self.DetectionRun = self.DetectionRun + 1 - - self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table - - for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do - local DetectionGroup = DetectionGroupData -- Wrapper.Group#GROUP - - if DetectionGroup:IsAlive() then - - local DetectionGroupName = DetectionGroup:GetName() - - local DetectionDetectedTargets = DetectionGroup:GetDetectedTargets( - self.DetectVisual, - self.DetectOptical, - self.DetectRadar, - self.DetectIRST, - self.DetectRWR, - self.DetectDLINK - ) - - for DetectionDetectedTargetID, DetectionDetectedTarget in pairs( DetectionDetectedTargets ) do - local DetectionObject = DetectionDetectedTarget.object -- Dcs.DCSWrapper.Object#Object - self:T2( DetectionObject ) - - if DetectionObject and DetectionObject:isExist() and DetectionObject.id_ < 50000000 then - - local DetectionDetectedObjectName = DetectionObject:getName() - - local DetectionDetectedObjectPositionVec3 = DetectionObject:getPoint() - local DetectionGroupVec3 = DetectionGroup:GetVec3() - - local Distance = ( ( DetectionDetectedObjectPositionVec3.x - DetectionGroupVec3.x )^2 + - ( DetectionDetectedObjectPositionVec3.y - DetectionGroupVec3.y )^2 + - ( DetectionDetectedObjectPositionVec3.z - DetectionGroupVec3.z )^2 - ) ^ 0.5 / 1000 - - self:T2( { DetectionGroupName, DetectionDetectedObjectName, Distance } ) - - if Distance <= self.DetectionRange then - - if not self.DetectedObjects[DetectionDetectedObjectName] then - self.DetectedObjects[DetectionDetectedObjectName] = {} - end - self.DetectedObjects[DetectionDetectedObjectName].Name = DetectionDetectedObjectName - self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible - self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type - self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance - else - -- if beyond the DetectionRange then nullify... - if self.DetectedObjects[DetectionDetectedObjectName] then - self.DetectedObjects[DetectionDetectedObjectName] = nil - end - end - end - end - - self:T2( self.DetectedObjects ) - - -- okay, now we have a list of detected object names ... - -- Sort the table based on distance ... - table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end ) - end - end - - if self.DetectedObjects then - self:CreateDetectionSets() - end - - return true -end - - - ---- DETECTION_AREAS class --- @type DETECTION_AREAS --- @field Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @field #DETECTION_AREAS.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange. --- @extends Functional.Detection#DETECTION_BASE -DETECTION_AREAS = { - ClassName = "DETECTION_AREAS", - DetectedAreas = { n = 0 }, - DetectionZoneRange = nil, -} - ---- @type DETECTION_AREAS.DetectedAreas --- @list <#DETECTION_AREAS.DetectedArea> - ---- @type DETECTION_AREAS.DetectedArea --- @field Core.Set#SET_UNIT Set -- The Set of Units in the detected area. --- @field Core.Zone#ZONE_UNIT Zone -- The Zone of the detected area. --- @field #boolean Changed Documents if the detected area has changes. --- @field #table Changes A list of the changes reported on the detected area. (It is up to the user of the detected area to consume those changes). --- @field #number AreaID -- The identifier of the detected area. --- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area. --- @field Wrapper.Unit#UNIT NearestFAC The nearest FAC near the Area. - - ---- DETECTION_AREAS constructor. --- @param Functional.Detection#DETECTION_AREAS self --- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role. --- @param Dcs.DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @param Dcs.DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @return Functional.Detection#DETECTION_AREAS self -function DETECTION_AREAS:New( DetectionSetGroup, DetectionRange, DetectionZoneRange ) - - -- Inherits from DETECTION_BASE - local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup, DetectionRange ) ) - - self.DetectionZoneRange = DetectionZoneRange - - self._SmokeDetectedUnits = false - self._FlareDetectedUnits = false - self._SmokeDetectedZones = false - self._FlareDetectedZones = false - - self:Schedule( 0, 30 ) - - return self -end - ---- Add a detected @{#DETECTION_AREAS.DetectedArea}. --- @param Core.Set#SET_UNIT Set -- The Set of Units in the detected area. --- @param Core.Zone#ZONE_UNIT Zone -- The Zone of the detected area. --- @return #DETECTION_AREAS.DetectedArea DetectedArea -function DETECTION_AREAS:AddDetectedArea( Set, Zone ) - local DetectedAreas = self:GetDetectedAreas() - DetectedAreas.n = self:GetDetectedAreaCount() + 1 - DetectedAreas[DetectedAreas.n] = {} - local DetectedArea = DetectedAreas[DetectedAreas.n] - DetectedArea.Set = Set - DetectedArea.Zone = Zone - DetectedArea.Removed = false - DetectedArea.AreaID = DetectedAreas.n - - return DetectedArea -end - ---- Remove a detected @{#DETECTION_AREAS.DetectedArea} with a given Index. --- @param #DETECTION_AREAS self --- @param #number Index The Index of the detection are to be removed. --- @return #nil -function DETECTION_AREAS:RemoveDetectedArea( Index ) - local DetectedAreas = self:GetDetectedAreas() - local DetectedAreaCount = self:GetDetectedAreaCount() - local DetectedArea = DetectedAreas[Index] - local DetectedAreaSet = DetectedArea.Set - DetectedArea[Index] = nil - return nil -end - - ---- Get the detected @{#DETECTION_AREAS.DetectedAreas}. --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS.DetectedAreas DetectedAreas -function DETECTION_AREAS:GetDetectedAreas() - - local DetectedAreas = self.DetectedAreas - return DetectedAreas -end - ---- Get the amount of @{#DETECTION_AREAS.DetectedAreas}. --- @param #DETECTION_AREAS self --- @return #number DetectedAreaCount -function DETECTION_AREAS:GetDetectedAreaCount() - - local DetectedAreaCount = self.DetectedAreas.n - return DetectedAreaCount -end - ---- Get the @{Core.Set#SET_UNIT} of a detecttion area using a given numeric index. --- @param #DETECTION_AREAS self --- @param #number Index --- @return Core.Set#SET_UNIT DetectedSet -function DETECTION_AREAS:GetDetectedSet( Index ) - - local DetectedSetUnit = self.DetectedAreas[Index].Set - if DetectedSetUnit then - return DetectedSetUnit - end - - return nil -end - ---- Get the @{Core.Zone#ZONE_UNIT} of a detection area using a given numeric index. --- @param #DETECTION_AREAS self --- @param #number Index --- @return Core.Zone#ZONE_UNIT DetectedZone -function DETECTION_AREAS:GetDetectedZone( Index ) - - local DetectedZone = self.DetectedAreas[Index].Zone - if DetectedZone then - return DetectedZone - end - - return nil -end - ---- Background worker function to determine if there are friendlies nearby ... --- @param #DETECTION_AREAS self --- @param Wrapper.Unit#UNIT ReportUnit -function DETECTION_AREAS:ReportFriendliesNearBy( ReportGroupData ) - self:F2() - - local DetectedArea = ReportGroupData.DetectedArea -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = ReportGroupData.DetectedArea.Set - local DetectedZone = ReportGroupData.DetectedArea.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT - - DetectedArea.FriendliesNearBy = false - - local SphereSearch = { - id = world.VolumeType.SPHERE, - params = { - point = DetectedZoneUnit:GetVec3(), - radius = 6000, - } - - } - - --- @param Dcs.DCSWrapper.Unit#Unit FoundDCSUnit - -- @param Wrapper.Group#GROUP ReportGroup - -- @param Set#SET_GROUP ReportSetGroup - local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData ) - - local DetectedArea = ReportGroupData.DetectedArea -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = ReportGroupData.DetectedArea.Set - local DetectedZone = ReportGroupData.DetectedArea.Zone - local DetectedZoneUnit = DetectedZone.ZoneUNIT -- Wrapper.Unit#UNIT - local ReportSetGroup = ReportGroupData.ReportSetGroup - - local EnemyCoalition = DetectedZoneUnit:GetCoalition() - - local FoundUnitCoalition = FoundDCSUnit:getCoalition() - local FoundUnitName = FoundDCSUnit:getName() - local FoundUnitGroupName = FoundDCSUnit:getGroup():getName() - local EnemyUnitName = DetectedZoneUnit:GetName() - local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil - - self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) - - if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then - DetectedArea.FriendliesNearBy = true - return false - end - - return true - end - - world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData ) - -end - - - ---- Returns if there are friendlies nearby the FAC units ... --- @param #DETECTION_AREAS self --- @return #boolean trhe if there are friendlies nearby -function DETECTION_AREAS:IsFriendliesNearBy( DetectedArea ) - - self:T3( DetectedArea.FriendliesNearBy ) - return DetectedArea.FriendliesNearBy or false -end - ---- Calculate the maxium A2G threat level of the DetectedArea. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea -function DETECTION_AREAS:CalculateThreatLevelA2G( DetectedArea ) - - local MaxThreatLevelA2G = 0 - for UnitName, UnitData in pairs( DetectedArea.Set:GetSet() ) do - local ThreatUnit = UnitData -- Wrapper.Unit#UNIT - local ThreatLevelA2G = ThreatUnit:GetThreatLevel() - if ThreatLevelA2G > MaxThreatLevelA2G then - MaxThreatLevelA2G = ThreatLevelA2G - end - end - - self:T3( MaxThreatLevelA2G ) - DetectedArea.MaxThreatLevelA2G = MaxThreatLevelA2G - -end - ---- Find the nearest FAC of the DetectedArea. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return Wrapper.Unit#UNIT The nearest FAC unit -function DETECTION_AREAS:NearestFAC( DetectedArea ) - - local NearestFAC = nil - local MinDistance = 1000000000 -- Units are not further than 1000000 km away from an area :-) - - for FACGroupName, FACGroupData in pairs( self.DetectionSetGroup:GetSet() ) do - for FACUnit, FACUnitData in pairs( FACGroupData:GetUnits() ) do - local FACUnit = FACUnitData -- Wrapper.Unit#UNIT - if FACUnit:IsActive() then - local Vec3 = FACUnit:GetVec3() - local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) - local Distance = PointVec3:Get2DDistance(POINT_VEC3:NewFromVec3( FACUnit:GetVec3() ) ) - if Distance < MinDistance then - MinDistance = Distance - NearestFAC = FACUnit - end - end - end - end - - DetectedArea.NearestFAC = NearestFAC - -end - ---- Returns the A2G threat level of the units in the DetectedArea --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #number a scale from 0 to 10. -function DETECTION_AREAS:GetTreatLevelA2G( DetectedArea ) - - self:T3( DetectedArea.MaxThreatLevelA2G ) - return DetectedArea.MaxThreatLevelA2G -end - - - ---- Smoke the detected units --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:SmokeDetectedUnits() - self:F2() - - self._SmokeDetectedUnits = true - return self -end - ---- Flare the detected units --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:FlareDetectedUnits() - self:F2() - - self._FlareDetectedUnits = true - return self -end - ---- Smoke the detected zones --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:SmokeDetectedZones() - self:F2() - - self._SmokeDetectedZones = true - return self -end - ---- Flare the detected zones --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:FlareDetectedZones() - self:F2() - - self._FlareDetectedZones = true - return self -end - ---- Add a change to the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @param #string ChangeCode --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AddChangeArea( DetectedArea, ChangeCode, AreaUnitType ) - - DetectedArea.Changed = true - local AreaID = DetectedArea.AreaID - - DetectedArea.Changes = DetectedArea.Changes or {} - DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {} - DetectedArea.Changes[ChangeCode].AreaID = AreaID - DetectedArea.Changes[ChangeCode].AreaUnitType = AreaUnitType - - self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, AreaUnitType } ) - - return self -end - - ---- Add a change to the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @param #string ChangeCode --- @param #string ChangeUnitType --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AddChangeUnit( DetectedArea, ChangeCode, ChangeUnitType ) - - DetectedArea.Changed = true - local AreaID = DetectedArea.AreaID - - DetectedArea.Changes = DetectedArea.Changes or {} - DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {} - DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] or 0 - DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] + 1 - DetectedArea.Changes[ChangeCode].AreaID = AreaID - - self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, ChangeUnitType } ) - - return self -end - ---- Make text documenting the changes of the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #string The Changes text -function DETECTION_AREAS:GetChangeText( DetectedArea ) - self:F( DetectedArea ) - - local MT = {} - - for ChangeCode, ChangeData in pairs( DetectedArea.Changes ) do - - if ChangeCode == "AA" then - MT[#MT+1] = "Detected new area " .. ChangeData.AreaID .. ". The center target is a " .. ChangeData.AreaUnitType .. "." - end - - if ChangeCode == "RAU" then - MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". Removed the center target." - end - - if ChangeCode == "AAU" then - MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". The new center target is a " .. ChangeData.AreaUnitType "." - end - - if ChangeCode == "RA" then - MT[#MT+1] = "Removed old area " .. ChangeData.AreaID .. ". No more targets in this area." - end - - if ChangeCode == "AU" then - local MTUT = {} - for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do - if ChangeUnitType ~= "AreaID" then - MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType - end - end - MT[#MT+1] = "Detected for area " .. ChangeData.AreaID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "." - end - - if ChangeCode == "RU" then - local MTUT = {} - for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do - if ChangeUnitType ~= "AreaID" then - MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType - end - end - MT[#MT+1] = "Removed for area " .. ChangeData.AreaID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "." - end - - end - - return table.concat( MT, "\n" ) - -end - - ---- Accepts changes from the detected zone. --- @param #DETECTION_AREAS self --- @param #DETECTION_AREAS.DetectedArea DetectedArea --- @return #DETECTION_AREAS self -function DETECTION_AREAS:AcceptChanges( DetectedArea ) - - DetectedArea.Changed = false - DetectedArea.Changes = {} - - return self -end - - ---- Make a DetectionSet table. This function will be overridden in the derived clsses. --- @param #DETECTION_AREAS self --- @return #DETECTION_AREAS self -function DETECTION_AREAS:CreateDetectionSets() - self:F2() - - -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. - -- Regroup when needed, split groups when needed. - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - if DetectedArea then - - local DetectedSet = DetectedArea.Set - - local AreaExists = false -- This flag will determine of the detected area is still existing. - - -- First test if the center unit is detected in the detection area. - self:T3( DetectedArea.Zone.ZoneUNIT.UnitName ) - local DetectedZoneObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName ) - self:T3( { "Detecting Zone Object", DetectedArea.AreaID, DetectedArea.Zone, DetectedZoneObject } ) - - if DetectedZoneObject then - - --self:IdentifyDetectedObject( DetectedZoneObject ) - AreaExists = true - - - - else - -- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area. - -- First remove the center unit from the set. - DetectedSet:RemoveUnitsByName( DetectedArea.Zone.ZoneUNIT.UnitName ) - - self:AddChangeArea( DetectedArea, 'RAU', "Dummy" ) - - -- Then search for a new center area unit within the set. Note that the new area unit candidate must be within the area range. - for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName ) - - -- The DetectedObject can be nil when the DetectedUnit is not alive anymore or it is not in the DetectedObjects map. - -- If the DetectedUnit was already identified, DetectedObject will be nil. - if DetectedObject then - self:IdentifyDetectedObject( DetectedObject ) - AreaExists = true - - -- Assign the Unit as the new center unit of the detected area. - DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange ) - - self:AddChangeArea( DetectedArea, "AAU", DetectedArea.Zone.ZoneUNIT:GetTypeName() ) - - -- We don't need to add the DetectedObject to the area set, because it is already there ... - break - end - end - end - - -- Now we've determined the center unit of the area, now we can iterate the units in the detected area. - -- Note that the position of the area may have moved due to the center unit repositioning. - -- If no center unit was identified, then the detected area does not exist anymore and should be deleted, as there are no valid units that can be the center unit. - if AreaExists then - - -- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ... - -- Those units within the zone are flagged as Identified. - -- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets. - for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - local DetectedObject = nil - if DetectedUnit:IsAlive() then - --self:E(DetectedUnit:GetName()) - DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() ) - end - if DetectedObject then - - -- Check if the DetectedUnit is within the DetectedArea.Zone - if DetectedUnit:IsInZone( DetectedArea.Zone ) then - - -- Yes, the DetectedUnit is within the DetectedArea.Zone, no changes, DetectedUnit can be kept within the Set. - self:IdentifyDetectedObject( DetectedObject ) - - else - -- No, the DetectedUnit is not within the DetectedArea.Zone, remove DetectedUnit from the Set. - DetectedSet:Remove( DetectedUnitName ) - self:AddChangeUnit( DetectedArea, "RU", DetectedUnit:GetTypeName() ) - end - - else - -- There was no DetectedObject, remove DetectedUnit from the Set. - self:AddChangeUnit( DetectedArea, "RU", "destroyed target" ) - DetectedSet:Remove( DetectedUnitName ) - - -- The DetectedObject has been identified, because it does not exist ... - -- self:IdentifyDetectedObject( DetectedObject ) - end - end - else - self:RemoveDetectedArea( DetectedAreaID ) - self:AddChangeArea( DetectedArea, "RA" ) - end - end - end - - -- We iterated through the existing detection areas and: - -- - We checked which units are still detected in each detection area. Those units were flagged as Identified. - -- - We recentered the detection area to new center units where it was needed. - -- - -- Now we need to loop through the unidentified detected units and see where they belong: - -- - They can be added to a new detection area and become the new center unit. - -- - They can be added to a new detection area. - for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do - - local DetectedObject = self:GetDetectedObject( DetectedUnitName ) - - if DetectedObject then - - -- We found an unidentified unit outside of any existing detection area. - local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Wrapper.Unit#UNIT - - local AddedToDetectionArea = false - - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - if DetectedArea then - self:T( "Detection Area #" .. DetectedArea.AreaID ) - local DetectedSet = DetectedArea.Set - if not self:IsDetectedObjectIdentified( DetectedObject ) and DetectedUnit:IsInZone( DetectedArea.Zone ) then - self:IdentifyDetectedObject( DetectedObject ) - DetectedSet:AddUnit( DetectedUnit ) - AddedToDetectionArea = true - self:AddChangeUnit( DetectedArea, "AU", DetectedUnit:GetTypeName() ) - end - end - end - - if AddedToDetectionArea == false then - - -- New detection area - local DetectedArea = self:AddDetectedArea( - SET_UNIT:New(), - ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - ) - --self:E( DetectedArea.Zone.ZoneUNIT.UnitName ) - DetectedArea.Set:AddUnit( DetectedUnit ) - self:AddChangeArea( DetectedArea, "AA", DetectedUnit:GetTypeName() ) - end - end - end - - -- Now all the tests should have been build, now make some smoke and flares... - -- We also report here the friendlies within the detected areas. - - for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do - - local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - self:ReportFriendliesNearBy( { DetectedArea = DetectedArea, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table - self:CalculateThreatLevelA2G( DetectedArea ) -- Calculate A2G threat level - self:NearestFAC( DetectedArea ) - - if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then - DetectedZone.ZoneUNIT:SmokeRed() - end - DetectedSet:ForEachUnit( - --- @param Wrapper.Unit#UNIT DetectedUnit - function( DetectedUnit ) - if DetectedUnit:IsAlive() then - self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() ) - if DETECTION_AREAS._FlareDetectedUnits or self._FlareDetectedUnits then - DetectedUnit:FlareGreen() - end - if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then - DetectedUnit:SmokeGreen() - end - end - end - ) - if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then - DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) ) - end - if DETECTION_AREAS._SmokeDetectedZones or self._SmokeDetectedZones then - DetectedZone:SmokeZone( SMOKECOLOR.White, 30 ) - end - end - -end - - ---- SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class. AI Balancing will replace in multi player missions --- non-occupied human slots with AI groups, in order to provide an engaging simulation environment, --- even when there are hardly any players in the mission. --- --- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) --- --- Examples can be found in the test missions. --- --- === --- --- # 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} --- --- The @{AI.AI_Balancer#AI_BALANCER} class monitors and manages as many replacement AI groups as there are --- CLIENTS in a SET_CLIENT collection, which are not occupied by human players. --- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. --- --- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM). --- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods. --- An explanation about state and event transition methods can be found in the @{FSM} module documentation. --- --- The mission designer can tailor the AI_BALANCER behaviour, by implementing a state or event handling method for the following: --- --- * **@{#AI_BALANCER.OnAfterSpawned}**( AISet, From, Event, To, AIGroup ): Define to add extra logic when an AI is spawned. --- --- ## 1.1) AI_BALANCER construction --- --- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: --- --- ## 1.2) AI_BALANCER is a FSM --- --- ![Process](..\Presentations\AI_Balancer\Dia13.JPG) --- --- ### 1.2.1) AI_BALANCER States --- --- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. --- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. --- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. --- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. --- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. --- --- ### 1.2.2) AI_BALANCER Events --- --- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. --- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. --- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. --- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. --- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. --- --- ## 1.3) AI_BALANCER spawn interval for replacement AI --- --- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. --- --- ## 1.4) AI_BALANCER returns AI to Airbases --- --- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. --- However, there are 2 additional options that you can use to customize the destroy behaviour. --- When a human player joins a slot, you can configure to let the AI return to: --- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. --- --- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return, --- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed. --- --- === --- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. --- --- === --- --- # **AUTHORS and CONTRIBUTIONS** --- --- ### Contributions: --- --- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) --- --- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. --- --- ### Authors: --- --- * FlightControl: Framework Design & Programming and Documentation. --- --- @module AI_Balancer - ---- AI_BALANCER class --- @type AI_BALANCER --- @field Core.Set#SET_CLIENT SetClient --- @field Functional.Spawn#SPAWN SpawnAI --- @field Wrapper.Group#GROUP Test --- @extends Core.Fsm#FSM_SET -AI_BALANCER = { - ClassName = "AI_BALANCER", - PatrolZones = {}, - AIGroups = {}, - Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. - Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. -} - - - ---- Creates a new AI_BALANCER object --- @param #AI_BALANCER self --- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). --- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. --- @return #AI_BALANCER -function AI_BALANCER:New( SetClient, SpawnAI ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER - - self:SetStartState( "None" ) - self:AddTransition( "*", "Monitor", "Monitoring" ) - self:AddTransition( "*", "Spawn", "Spawning" ) - self:AddTransition( "Spawning", "Spawned", "Spawned" ) - self:AddTransition( "*", "Destroy", "Destroying" ) - self:AddTransition( "*", "Return", "Returning" ) - - self.SetClient = SetClient - self.SetClient:FilterOnce() - self.SpawnAI = SpawnAI - - self.SpawnQueue = {} - - self.ToNearestAirbase = false - self.ToHomeAirbase = false - - self:__Monitor( 1 ) - - return self -end - ---- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. --- Provide 2 identical seconds if the interval should be a fixed amount of seconds. --- @param #AI_BALANCER self --- @param #number Earliest The earliest a new AI can be spawned in seconds. --- @param #number Latest The latest a new AI can be spawned in seconds. --- @return self -function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) - - self.Earliest = Earliest - self.Latest = Latest - - return self -end - ---- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. --- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. --- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to. -function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) - - self.ToNearestAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange - self.ReturnAirbaseSet = ReturnAirbaseSet -end - ---- Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. --- @param #AI_BALANCER self --- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. -function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) - - self.ToHomeAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param #string ClientName --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) - - -- OK, Spawn a new group from the default SpawnAI object provided. - local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP - AIGroup:E( "Spawning new AIGroup" ) - --TODO: need to rework UnitName thing ... - - SetGroup:Add( ClientName, AIGroup ) - self.SpawnQueue[ClientName] = nil - - -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. - -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) - - AIGroup:Destroy() - SetGroup:Flush() - SetGroup:Remove( ClientName ) - SetGroup:Flush() -end - ---- @param #AI_BALANCER self --- @param Core.Set#SET_GROUP SetGroup --- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup ) - - local AIGroupTemplate = AIGroup:GetTemplate() - if self.ToHomeAirbase == true then - local WayPointCount = #AIGroupTemplate.route.points - local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) - AIGroup:SetCommand( SwitchWayPointCommand ) - AIGroup:MessageToRed( "Returning to home base ...", 30 ) - else - -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. - --TODO: i need to rework the POINT_VEC2 thing. - local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) - local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) - self:T( ClosestAirbase.AirbaseName ) - AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) - local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) - AIGroupTemplate.route = RTBRoute - AIGroup:Respawn( AIGroupTemplate ) - end - -end - - ---- @param #AI_BALANCER self -function AI_BALANCER:onenterMonitoring( SetGroup ) - - self:E( { self.SetClient:Count() } ) - self.SetClient:Flush() - - self.SetClient:ForEachClient( - --- @param Wrapper.Client#CLIENT Client - function( Client ) - self:E(Client.ClientName) - - local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP - self:E({Client:IsAlive()}) - if Client:IsAlive() then - - if AIGroup and AIGroup:IsAlive() == true then - - if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - self:Destroy( Client.UnitName, AIGroup ) - else - -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. - -- If there is a CLIENT, the AI stays engaged and will not return. - -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. - - local PlayerInRange = { Value = false } - local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) - - self:E( RangeZone ) - - _DATABASE:ForEachPlayer( - --- @param Wrapper.Unit#UNIT RangeTestUnit - function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) - self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) - if RangeTestUnit:IsInZone( RangeZone ) == true then - self:E( "in zone" ) - if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then - self:E( "in range" ) - PlayerInRange.Value = true - end - end - end, - - --- @param Core.Zone#ZONE_RADIUS RangeZone - -- @param Wrapper.Group#GROUP AIGroup - function( RangeZone, AIGroup, PlayerInRange ) - if PlayerInRange.Value == false then - self:Return( AIGroup ) - end - end - , RangeZone, AIGroup, PlayerInRange - ) - - end - self.Set:Remove( Client.UnitName ) - end - else - if not AIGroup or not AIGroup:IsAlive() == true then - self:E( "Client " .. Client.UnitName .. " not alive." ) - if not self.SpawnQueue[Client.UnitName] then - -- Spawn a new AI taking into account the spawn interval Earliest, Latest - self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) - self.SpawnQueue[Client.UnitName] = true - self:E( "New AI Spawned for Client " .. Client.UnitName ) - end - end - end - return true - end - ) - - self:__Monitor( 10 ) -end - - - ---- (AI) (FSM) Make AI patrol routes or zones. --- --- === --- --- 1) @{#AI_PATROLZONE} class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- ================================================================ --- The @{#AI_PATROLZONE} class implements the core functions to patrol a @{Zone} by an AIR @{Controllable} @{Group}. --- The patrol algorithm works that for each airplane patrolling, upon arrival at the patrol zone, --- a random point is selected as the route point within the 3D space, within the given boundary limits. --- The airplane will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. --- Upon arrival at the random 3D point, a new 3D random point will be selected within the patrol zone using the given limits. --- This cycle will continue until a fuel treshold has been reached by the airplane. --- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. --- --- 1.1) AI_PATROLZONE constructor: --- ---------------------------- --- --- * @{#AI_PATROLZONE.New}(): Creates a new AI_PATROLZONE object. --- --- 1.2) AI_PATROLZONE state machine: --- ---------------------------------- --- The AI_PATROLZONE is a state machine: it manages the different events and states of the AIControllable it is controlling. --- --- ### 1.2.1) AI_PATROLZONE Events: --- --- * @{#AI_PATROLZONE.Route}( AIControllable ): A new 3D route point is selected and the AIControllable will fly towards that point with the given speed. --- * @{#AI_PATROLZONE.Patrol}( AIControllable ): The AIControllable reports it is patrolling. This event is called every 30 seconds. --- * @{#AI_PATROLZONE.RTB}( AIControllable ): The AIControllable will report return to base. --- * @{#AI_PATROLZONE.End}( AIControllable ): The end of the AI_PATROLZONE process. --- * @{#AI_PATROLZONE.Dead}( AIControllable ): The AIControllable is dead. The AI_PATROLZONE process will be ended. --- --- ### 1.2.2) AI_PATROLZONE States: --- --- * **Route**: A new 3D route point is selected and the AIControllable will fly towards that point with the given speed. --- * **Patrol**: The AIControllable is patrolling. This state is set every 30 seconds, so every 30 seconds, a state transition method can be used. --- * **RTB**: The AIControllable reports it wants to return to the base. --- * **Dead**: The AIControllable is dead ... --- * **End**: The process has come to an end. --- --- ### 1.2.3) AI_PATROLZONE state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- An example how to manage a state transition for an AI_PATROLZONE object **Patrol** for the state **RTB**: --- --- local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone" ) --- local PatrolZone = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) --- --- local PatrolSpawn = SPAWN:New( "Patrol Group" ) --- local PatrolGroup = PatrolSpawn:Spawn() --- --- local Patrol = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 300, 600 ) --- Patrol:SetControllable( PatrolGroup ) --- Patrol:ManageFuel( 0.2, 60 ) --- --- **OnBefore**RTB( AIGroup ) will be called by the AI_PATROLZONE object when the AIGroup reports RTB, but **before** the RTB default action is processed by the AI_PATROLZONE object. --- --- --- State transition function for the AI_PATROLZONE **Patrol** object --- -- @param #AI_PATROLZONE self --- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup --- -- @return #boolean If false is returned, then the OnAfter state transition method will not be called. --- function Patrol:OnBeforeRTB( AIGroup ) --- AIGroup:MessageToRed( "Returning to base", 20 ) --- end --- --- **OnAfter**RTB( AIGroup ) will be called by the AI_PATROLZONE object when the AIGroup reports RTB, but **after** the RTB default action was processed by the AI_PATROLZONE object. --- --- --- State transition function for the AI_PATROLZONE **Patrol** object --- -- @param #AI_PATROLZONE self --- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup --- -- @return #Wrapper.Controllable#CONTROLLABLE The new AIGroup object that is set to be patrolling the zone. --- function Patrol:OnAfterRTB( AIGroup ) --- return PatrolSpawn:Spawn() --- end --- --- 1.3) Manage the AI_PATROLZONE parameters: --- ------------------------------------------ --- The following methods are available to modify the parameters of a AI_PATROLZONE object: --- --- * @{#AI_PATROLZONE.SetControllable}(): Set the AIControllable. --- * @{#AI_PATROLZONE.GetControllable}(): Get the AIControllable. --- * @{#AI_PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol. --- * @{#AI_PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol. --- --- 1.3) Manage the out of fuel in the AI_PATROLZONE: --- ---------------------------------------------- --- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base. --- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. --- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROLZONE. --- Once the time is finished, the old AIControllable will return to the base. --- Use the method @{#AI_PATROLZONE.ManageFuel}() to have this proces in place. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-09-01: Initial class and API. --- --- === --- --- AUTHORS and CONTRIBUTIONS --- ========================= --- --- ### Contributions: --- --- * **DutchBaron**: Testing. --- * **Pikey**: Testing and API concept review. --- --- ### Authors: --- --- * **FlightControl**: Design & Programming. --- --- --- @module AI_Patrol - ---- AI_PATROLZONE class --- @type AI_PATROLZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. --- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @extends Core.Fsm#FSM_CONTROLLABLE -AI_PATROLZONE = { - ClassName = "AI_PATROLZONE", -} - - - ---- Creates a new AI_PATROLZONE object --- @param #AI_PATROLZONE self --- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @return #AI_PATROLZONE self --- @usage --- -- Define a new AI_PATROLZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. --- PatrolZone = ZONE:New( 'PatrolZone' ) --- PatrolSpawn = SPAWN:New( 'Patrol Group' ) --- PatrolArea = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 600, 900 ) -function AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_CONTROLLABLE - - - self.PatrolZone = PatrolZone - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed - - self.PatrolFuelTresholdPercentage = 0.2 - - - self:SetStartState( "None" ) - -do self:AddTransition( "*", "Start", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnBeforeStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Start. - -- @function [parent=#AI_PATROLZONE] OnAfterStart - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Start. - -- @function [parent=#AI_PATROLZONE] Start - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Start - -- @function [parent=#AI_PATROLZONE] __Start - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "*", "Route", "Route" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnLeaveRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnEnterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnBeforeRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Route. - -- @function [parent=#AI_PATROLZONE] OnAfterRoute - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Route. - -- @function [parent=#AI_PATROLZONE] Route - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Route - -- @function [parent=#AI_PATROLZONE] __Route - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "*", "Patrol", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnEnterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnBeforePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnAfterPatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Patrol. - -- @function [parent=#AI_PATROLZONE] Patrol - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for Patrol - -- @function [parent=#AI_PATROLZONE] __Patrol - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - -do self:AddTransition( "Patrol", "RTB", "RTB" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROLZONE. - - --- OnLeave State Transition for Patrol. - -- @function [parent=#AI_PATROLZONE] OnLeavePatrol - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnEnterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnBeforeRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for RTB. - -- @function [parent=#AI_PATROLZONE] OnAfterRTB - -- @param #AI_PATROLZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for RTB. - -- @function [parent=#AI_PATROLZONE] RTB - -- @param #AI_PATROLZONE self - - --- Delayed Event Trigger for RTB - -- @function [parent=#AI_PATROLZONE] __RTB - -- @param #AI_PATROLZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_PATROLZONE - - return self -end - - - - ---- Sets (modifies) the minimum and maximum speed of the patrol. --- @param #AI_PATROLZONE self --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) - self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) - - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed -end - - - ---- Sets the floor and ceiling altitude of the patrol. --- @param #AI_PATROLZONE self --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) - self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) - - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude -end - - - ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewPatrolRoute( AIControllable ) - - AIControllable:T( "NewPatrolRoute" ) - local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolCore.Zone#AI_PATROLZONE - PatrolZone:__Route( 1 ) -end - - - - ---- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base. --- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. --- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROLZONE. --- Once the time is finished, the old AIControllable will return to the base. --- @param #AI_PATROLZONE self --- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. --- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. --- @return #AI_PATROLZONE self -function AI_PATROLZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime ) - - self.PatrolManageFuel = true - self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage - self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime - - return self -end - ---- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. --- @param #AI_PATROLZONE self --- @return #AI_PATROLZONE self -function AI_PATROLZONE:onenterRoute() - - self:F2() - - local PatrolRoute = {} - - if self.Controllable:IsAlive() then - --- Determine if the AIControllable is within the PatrolZone. - -- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point. - --- --- Calculate the current route point. --- local CurrentVec2 = self.Controllable:GetVec2() --- local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() --- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) --- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( --- POINT_VEC3.RoutePointAltType.BARO, --- POINT_VEC3.RoutePointType.TurningPoint, --- POINT_VEC3.RoutePointAction.TurningPoint, --- ToPatrolZoneSpeed, --- true --- ) --- --- PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint - - self:T2( PatrolRoute ) - - if self.Controllable:IsNotInZone( self.PatrolZone ) then - --- Find a random 2D point in PatrolZone. - local ToPatrolZoneVec2 = self.PatrolZone:GetRandomVec2() - self:T2( ToPatrolZoneVec2 ) - - --- Define Speed and Altitude. - local ToPatrolZoneAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) - local ToPatrolZoneSpeed = self.PatrolMaxSpeed - self:T2( ToPatrolZoneSpeed ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToPatrolZonePointVec3 = POINT_VEC3:New( ToPatrolZoneVec2.x, ToPatrolZoneAltitude, ToPatrolZoneVec2.y ) - - --- Create a route point of type air. - local ToPatrolZoneRoutePoint = ToPatrolZonePointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToPatrolZoneSpeed, - true - ) - - PatrolRoute[#PatrolRoute+1] = ToPatrolZoneRoutePoint - - end - - --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. - - --- Find a random 2D point in PatrolZone. - local ToTargetVec2 = self.PatrolZone:GetRandomVec2() - self:T2( ToTargetVec2 ) - - --- Define Speed and Altitude. - local ToTargetAltitude = math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) - local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) - self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) - - --- Create a route point of type air. - local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - --ToTargetPointVec3:SmokeRed() - - PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint - - --- 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( PatrolRoute ) - - --- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ... - self.Controllable:SetState( self.Controllable, "PatrolZone", self ) - self.Controllable:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" ) - - --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) - - self:__Patrol( 30 ) - end - -end - - ---- @param #AI_PATROLZONE self -function AI_PATROLZONE:onenterPatrol() - self:F2() - - if self.Controllable and self.Controllable:IsAlive() then - - local Fuel = self.Controllable:GetUnit(1):GetFuel() - if Fuel < self.PatrolFuelTresholdPercentage then - local OldAIControllable = self.Controllable - local AIControllableTemplate = self.Controllable:GetTemplate() - - local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) - local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) ) - OldAIControllable:SetTask( TimedOrbitTask, 10 ) - - self:RTB() - else - self:__Patrol( 30 ) -- Execute the Patrol event after 30 seconds. - end - end - -end ---- Management of logical cargo objects, that can be transported from and to transportation carriers. --- --- === --- --- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): --- --- * AI_CARGO_UNIT, represented by a @{Unit} in a @{Group}: Cargo can be represented by a Unit in a Group. Destruction of the Unit will mean that the cargo is lost. --- * CARGO_STATIC, represented by a @{Static}: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost. --- * AI_CARGO_PACKAGE, contained in a @{Unit} of a @{Group}: Cargo can be contained within a Unit of a Group. The cargo can be **delivered** by the @{Unit}. If the Unit is destroyed, the cargo will be destroyed also. --- * AI_CARGO_PACKAGE, Contained in a @{Static}: Cargo can be contained within a Static. The cargo can be **collected** from the @Static. If the @{Static} is destroyed, the cargo will be destroyed. --- * CARGO_SLINGLOAD, represented by a @{Cargo} that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost. --- --- * AI_CARGO_GROUPED, represented by a Group of CARGO_UNITs. --- --- 1) @{AI.AI_Cargo#AI_CARGO} class, extends @{Core.Fsm#FSM_PROCESS} --- ========================================================================== --- The @{#AI_CARGO} class defines the core functions that defines a cargo object within MOOSE. --- A cargo is a logical object defined that is available for transport, and has a life status within a simulation. --- --- The AI_CARGO is a state machine: it manages the different events and states of the cargo. --- All derived classes from AI_CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. --- --- ## 1.2.1) AI_CARGO Events: --- --- * @{#AI_CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. --- * @{#AI_CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. --- * @{#AI_CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. --- * @{#AI_CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. --- * @{#AI_CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. --- --- ## 1.2.2) AI_CARGO States: --- --- * **UnLoaded**: The cargo is unloaded from a carrier. --- * **Boarding**: The cargo is currently boarding (= running) into a carrier. --- * **Loaded**: The cargo is loaded into a carrier. --- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. --- * **Dead**: The cargo is dead ... --- * **End**: The process has come to an end. --- --- ## 1.2.3) AI_CARGO state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Leaving** the state. --- The state transition method needs to start with the name **OnLeave + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **Entering** the state. --- The state transition method needs to start with the name **OnEnter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- 2) #AI_CARGO_UNIT class --- ==================== --- The AI_CARGO_UNIT class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. --- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. --- --- 5) #AI_CARGO_GROUPED class --- ======================= --- The AI_CARGO_GROUPED class defines a cargo that is represented by a group of UNIT objects within the simulator, and can be transported by a carrier. --- Use the event functions as described above to Load, UnLoad, Board, UnBoard the AI_CARGO_UNIT objects to and from carriers. --- --- This module is still under construction, but is described above works already, and will keep working ... --- --- @module Cargo - --- Events - --- Board - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] Board --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] __Board --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnBoard - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] UnBoard --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] __UnBoard --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - - --- Load - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] Load --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#AI_CARGO] __Load --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnLoad - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] UnLoad --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#AI_CARGO] __UnLoad --- @param #AI_CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - --- State Transition Functions - --- UnLoaded - ---- @function [parent=#AI_CARGO] OnLeaveUnLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterUnLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Loaded - ---- @function [parent=#AI_CARGO] OnLeaveLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterLoaded --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Boarding - ---- @function [parent=#AI_CARGO] OnLeaveBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- UnBoarding - ---- @function [parent=#AI_CARGO] OnLeaveUnBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#AI_CARGO] OnEnterUnBoarding --- @param #AI_CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - - --- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. - -CARGOS = {} - -do -- AI_CARGO - - --- @type AI_CARGO - -- @extends Core.Fsm#FSM_PROCESS - -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. - -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. - -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. - -- @field #number ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier. - -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. - -- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... - -- @field Wrapper.Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... - -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. - -- @field #boolean Moveable This flag defines if the cargo is moveable. - -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. - -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - AI_CARGO = { - ClassName = "AI_CARGO", - Type = nil, - Name = nil, - Weight = nil, - CargoObject = nil, - CargoCarrier = nil, - Representable = false, - Slingloadable = false, - Moveable = false, - Containable = false, - } - ---- @type AI_CARGO.CargoObjects --- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - - ---- AI_CARGO Constructor. This class is an abstract class and should not be instantiated. --- @param #AI_CARGO self --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO -function AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) - - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:SetStartState( "UnLoaded" ) - self:AddTransition( "UnLoaded", "Board", "Boarding" ) - self:AddTransition( "Boarding", "Boarding", "Boarding" ) - self:AddTransition( "Boarding", "Load", "Loaded" ) - self:AddTransition( "UnLoaded", "Load", "Loaded" ) - self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) - self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) - - - self.Type = Type - self.Name = Name - self.Weight = Weight - self.ReportRadius = ReportRadius - self.NearRadius = NearRadius - self.CargoObject = nil - self.CargoCarrier = nil - self.Representable = false - self.Slingloadable = false - self.Moveable = false - self.Containable = false - - - self.CargoScheduler = SCHEDULER:New() - - CARGOS[self.Name] = self - - return self -end - - ---- Template method to spawn a new representation of the AI_CARGO in the simulator. --- @param #AI_CARGO self --- @return #AI_CARGO -function AI_CARGO:Spawn( PointVec2 ) - self:F() - -end - - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #AI_CARGO self --- @param Core.Point#POINT_VEC2 PointVec2 --- @return #boolean -function AI_CARGO:IsNear( PointVec2 ) - self:F( { PointVec2 } ) - - local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - -end - -do -- AI_CARGO_REPRESENTABLE - - --- @type AI_CARGO_REPRESENTABLE - -- @extends #AI_CARGO - AI_CARGO_REPRESENTABLE = { - ClassName = "AI_CARGO_REPRESENTABLE" - } - ---- AI_CARGO_REPRESENTABLE Constructor. --- @param #AI_CARGO_REPRESENTABLE self --- @param Wrapper.Controllable#Controllable CargoObject --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_REPRESENTABLE -function AI_CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - return self -end - ---- Route a cargo unit to a PointVec2. --- @param #AI_CARGO_REPRESENTABLE self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #number Speed --- @return #AI_CARGO_REPRESENTABLE -function AI_CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:F2( ToPointVec2 ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) - Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - return self -end - -end -- AI_CARGO - -do -- AI_CARGO_UNIT - - --- @type AI_CARGO_UNIT - -- @extends #AI_CARGO_REPRESENTABLE - AI_CARGO_UNIT = { - ClassName = "AI_CARGO_UNIT" - } - ---- AI_CARGO_UNIT Constructor. --- @param #AI_CARGO_UNIT self --- @param Wrapper.Unit#UNIT CargoUnit --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_UNIT -function AI_CARGO_UNIT:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_UNIT - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:T( CargoUnit ) - self.CargoObject = CargoUnit - - self:T( self.ClassName ) - - return self -end - ---- Enter UnBoarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2 ) - self:F() - - local Angle = 180 - local Speed = 10 - local DeployDistance = 5 - local RouteDistance = 60 - - if From == "Loaded" then - - local CargoCarrierPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, CargoDeployHeading ) - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 - - local FromPointVec2 = CargoCarrierPointVec2 - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) - self.CargoCarrier = nil - - local Points = {} - Points[#Points+1] = FromPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = ToPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - - self:__UnBoarding( 1, ToPointVec2 ) - end - end - -end - ---- Leave UnBoarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - if self:IsNear( ToPointVec2 ) then - return true - else - self:__UnBoarding( 1, ToPointVec2 ) - end - return false - end - -end - ---- UnBoard Event. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 ToPointVec2 -function AI_CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - end - - self:__UnLoad( 1, ToPointVec2 ) - -end - - - ---- Enter UnLoaded State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Core.Point#POINT_VEC2 -function AI_CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "Loaded" then - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or POINT_VEC2:New( CargoDeployPointVec2:GetX(), CargoDeployPointVec2:GetY() ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - -end - - - ---- Enter Boarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local Speed = 10 - local Angle = 180 - local Distance = 5 - - if From == "UnLoaded" then - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - end - -end - ---- Leave Boarding State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if self:IsNear( CargoCarrier:GetPointVec2() ) then - self:__Load( 1, CargoCarrier ) - return true - else - self:__Boarding( 1, CargoCarrier ) - end - return false -end - ---- Loaded State. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:F() - - self.CargoCarrier = CargoCarrier - - -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self:T("Destroying") - self.CargoObject:Destroy() - end -end - - ---- Board Event. --- @param #AI_CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier ) - self:F() - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only move the group to the carrier when the cargo is not in the air - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - self:Load( CargoCarrier ) - end - -end - -end - -do -- AI_CARGO_PACKAGE - - --- @type AI_CARGO_PACKAGE - -- @extends #AI_CARGO_REPRESENTABLE - AI_CARGO_PACKAGE = { - ClassName = "AI_CARGO_PACKAGE" - } - ---- AI_CARGO_PACKAGE Constructor. --- @param #AI_CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_PACKAGE -function AI_CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #AI_CARGO_PACKAGE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) - - self:T( CargoCarrier ) - self.CargoCarrier = CargoCarrier - - return self -end - ---- Board Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number BoardDistance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. - if not self.CargoInAir then - - local Points = {} - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - -end - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #AI_CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier --- @return #boolean -function AI_CARGO_PACKAGE:IsNear( CargoCarrier ) - self:F() - - local CargoCarrierPoint = CargoCarrier:GetPointVec2() - - local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - ---- Boarded Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) - else - self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - end -end - ---- UnBoard Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Speed --- @param #number UnLoadDistance --- @param #number UnBoardDistance --- @param #number Radius --- @param #number Angle -function AI_CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:F() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier is not in the air. - -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). - if not self.CargoInAir then - - self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) - - local Points = {} - - local StartPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = CargoCarrier:TaskRoute( Points ) - CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:__UnBoarded( 1 , CargoCarrier, Speed ) - -end - ---- UnBoarded Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:F() - - if self:IsNear( CargoCarrier ) then - self:__UnLoad( 1, CargoCarrier, Speed ) - else - self:__UnBoarded( 1, CargoCarrier, Speed ) - end -end - ---- Load Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number LoadDistance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:F() - - self.CargoCarrier = CargoCarrier - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) - - local Points = {} - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - ---- UnLoad Event. --- @param #AI_CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param #number Distance --- @param #number Angle -function AI_CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) - self:F() - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - self.CargoCarrier = CargoCarrier - - local Points = {} - Points[#Points+1] = StartPointVec2:RoutePointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - - -end - -do -- AI_CARGO_GROUP - - --- @type AI_CARGO_GROUP - -- @extends AI.AI_Cargo#AI_CARGO - -- @field Set#SET_BASE CargoSet A set of cargo objects. - -- @field #string Name A string defining the name of the cargo group. The name is the unique identifier of the cargo. - AI_CARGO_GROUP = { - ClassName = "AI_CARGO_GROUP", - } - ---- AI_CARGO_GROUP constructor. --- @param #AI_CARGO_GROUP self --- @param Core.Set#Set_BASE CargoSet --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_GROUP -function AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO:New( Type, Name, 0, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUP - self:F( { Type, Name, ReportRadius, NearRadius } ) - - self.CargoSet = CargoSet - - - return self -end - -end -- AI_CARGO_GROUP - -do -- AI_CARGO_GROUPED - - --- @type AI_CARGO_GROUPED - -- @extends AI.AI_Cargo#AI_CARGO_GROUP - AI_CARGO_GROUPED = { - ClassName = "AI_CARGO_GROUPED", - } - ---- AI_CARGO_GROUPED constructor. --- @param #AI_CARGO_GROUPED self --- @param Core.Set#Set_BASE CargoSet --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #AI_CARGO_GROUPED -function AI_CARGO_GROUPED:New( CargoSet, Type, Name, ReportRadius, NearRadius ) - local self = BASE:Inherit( self, AI_CARGO_GROUP:New( CargoSet, Type, Name, ReportRadius, NearRadius ) ) -- #AI_CARGO_GROUPED - self:F( { Type, Name, ReportRadius, NearRadius } ) - - return self -end - ---- Enter Boarding State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if From == "UnLoaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:__Board( 1, CargoCarrier ) - end - ) - - self:__Boarding( 1, CargoCarrier ) - end - -end - ---- Enter Loaded State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterLoaded( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if From == "UnLoaded" then - -- For each Cargo object within the AI_CARGO_GROUPED, load each cargo to the CargoCarrier. - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) - end - end -end - ---- Leave Boarding State. --- @param #AI_CARGO_GROUPED self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onleaveBoarding( From, Event, To, CargoCarrier ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local Boarded = true - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "Loaded" ) then - Boarded = false - end - end - - if not Boarded then - self:__Boarding( 1, CargoCarrier ) - else - self:__Load( 1, CargoCarrier ) - end - return Boarded -end - ---- Enter UnBoarding State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterUnBoarding( From, Event, To, ToPointVec2 ) - self:F() - - local Timer = 1 - - if From == "Loaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:__UnBoard( Timer, ToPointVec2 ) - Timer = Timer + 10 - end - ) - - self:__UnBoarding( 1, ToPointVec2 ) - end - -end - ---- Leave UnBoarding State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onleaveUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) then - UnBoarded = false - end - end - - if UnBoarded then - return true - else - self:__UnBoarding( 1, ToPointVec2 ) - end - - return false - end - -end - ---- UnBoard Event. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onafterUnBoarding( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - self:__UnLoad( 1, ToPointVec2 ) -end - - - ---- Enter UnLoaded State. --- @param #AI_CARGO_GROUPED self --- @param Core.Point#POINT_VEC2 --- @param #string Event --- @param #string From --- @param #string To -function AI_CARGO_GROUPED:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) - - if From == "Loaded" then - - -- For each Cargo object within the AI_CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:UnLoad( ToPointVec2 ) - end - ) - - end - -end - -end -- AI_CARGO_GROUPED - - - ---- SP:Y MP:Y AI:Y HU:N TYP:Air -- This module contains the AI_CAS_ZONE class. --- --- === --- --- 1) @{#AI_CAS_ZONE} class, extends @{Core.Fsm#FSM_CONTROLLABLE} --- ================================================================ --- The @{#AI_CAS_ZONE} class implements the core functions to CAS a @{Zone} by an AIR @{Controllable} @{Group}. --- --- 1.1) AI_CAS_ZONE constructor: --- ---------------------------- --- --- * @{#AI_CAS_ZONE.New}(): Creates a new AI_CAS_ZONE object. --- --- 1.2) AI_CAS_ZONE state machine: --- ---------------------------------- --- The AI_CAS_ZONE is a state machine: it manages the different events and states of the AIControllable it is controlling. --- --- ### 1.2.1) AI_CAS_ZONE Events: --- --- * @{#AI_CAS_ZONE.TakeOff}( AIControllable ): The AI is taking-off from an airfield. --- * @{#AI_CAS_ZONE.Hold}( AIControllable ): The AI is holding in airspace at a zone. --- * @{#AI_CAS_ZONE.Engage}( AIControllable ): The AI is engaging the targets. --- * @{#AI_CAS_ZONE.WeaponReleased}( AIControllable ): The AI has released a weapon to the target. --- * @{#AI_CAS_ZONE.Destroy}( AIControllable ): The AI has destroyed a target. --- * @{#AI_CAS_ZONE.Complete}( AIControllable ): The AI has destroyed all defined targets. --- * @{#AI_CAS_ZONE.RTB}( AIControllable ): The AI is returning to the home base. --- --- ### 1.2.2) AI_CAS_ZONE States: --- --- --- ### 1.2.3) AI_CAS_ZONE state transition methods: --- --- --- 1.3) Manage the AI_CAS_ZONE parameters: --- ------------------------------------------ --- The following methods are available to modify the parameters of an AI_CAS_ZONE object: --- --- * @{#AI_CAS_ZONE.SetControllable}(): Set the AIControllable. --- * @{#AI_CAS_ZONE.GetControllable}(): Get the AIControllable. --- --- ==== --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2017-01-12: Initial class and API. --- --- === --- --- AUTHORS and CONTRIBUTIONS --- ========================= --- --- ### Contributions: --- --- * **Quax**: Concept & Testing. --- * **Pikey**: Concept & Testing. --- --- ### Authors: --- --- * **FlightControl**: Concept, Design & Programming. --- --- --- @module Cas - - ---- AI_CAS_ZONE class --- @type AI_CAS_ZONE --- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. --- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. --- @extends AI.AI_Patrol#AI_PATROLZONE -AI_CAS_ZONE = { - ClassName = "AI_CAS_ZONE", -} - - - ---- Creates a new AI_CAS_ZONE object --- @param #AI_CAS_ZONE self --- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. --- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. --- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. --- @param Core.Zone#ZONE EngageZone --- @return #AI_CAS_ZONE self -function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) ) -- #AI_CAS_ZONE - - self.PatrolZone = PatrolZone - self.PatrolFloorAltitude = PatrolFloorAltitude - self.PatrolCeilingAltitude = PatrolCeilingAltitude - self.PatrolMinSpeed = PatrolMinSpeed - self.PatrolMaxSpeed = PatrolMaxSpeed - - self.EngageZone = EngageZone - - do self:AddTransition( { "Patrol", "Route", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Holding. - -- @function [parent=#AI_CAS_ZONE] OnLeaveHolding - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnBeforeEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Engage. - -- @function [parent=#AI_CAS_ZONE] OnAfterEngage - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Engage. - -- @function [parent=#AI_CAS_ZONE] Engage - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Engage - -- @function [parent=#AI_CAS_ZONE] __Engage - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - - do self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnBeforeFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Fired. - -- @function [parent=#AI_CAS_ZONE] OnAfterFired - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean - - --- Embedded Event Trigger for Fired. - -- @function [parent=#AI_CAS_ZONE] Fired - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Fired - -- @function [parent=#AI_CAS_ZONE] __Fired - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - do self:AddTransition( "Engaging", "Destroy", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnEnterEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnBeforeDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Destroy. - -- @function [parent=#AI_CAS_ZONE] OnAfterDestroy - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Destroy. - -- @function [parent=#AI_CAS_ZONE] Destroy - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Destroy - -- @function [parent=#AI_CAS_ZONE] __Destroy - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - -do self:AddTransition( "Engaging", "Abort", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Abort. - -- @function [parent=#AI_CAS_ZONE] OnBeforeAbort - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Abort. - -- @function [parent=#AI_CAS_ZONE] OnAfterAbort - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Abort. - -- @function [parent=#AI_CAS_ZONE] Abort - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Abort - -- @function [parent=#AI_CAS_ZONE] __Abort - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - -end -- AI_CAS_ZONE - - - do self:AddTransition( "Engaging", "Completed", "Patrol" ) -- FSM_CONTROLLABLE Transition for type #AI_CAS_ZONE. - - --- OnLeave State Transition for Engaging. - -- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnEnter State Transition for Patrol. - -- @function [parent=#AI_CAS_ZONE] OnEnterPatrol - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- OnBefore State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnBeforeCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter State Transition for Completed. - -- @function [parent=#AI_CAS_ZONE] OnAfterCompleted - -- @param #AI_CAS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Embedded Event Trigger for Completed. - -- @function [parent=#AI_CAS_ZONE] Completed - -- @param #AI_CAS_ZONE self - - --- Delayed Event Trigger for Completed - -- @function [parent=#AI_CAS_ZONE] __Completed - -- @param #AI_CAS_ZONE self - -- @param #number Delay The delay in seconds. - - end -- AI_CAS_ZONE - - return self -end - - ---- onafter State Transition for Event Start. --- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To ) - - - if Controllable:IsAlive() then - self:__Route( 1 ) - end - - self:EventOnDead( self.OnDead ) - - Controllable:OptionROEHoldFire() - Controllable:OptionROTVertical() - -end - ---- @param Wrapper.Controllable#CONTROLLABLE AIControllable -function _NewEngageRoute( AIControllable ) - - AIControllable:T( "NewEngageRoute" ) - local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Patrol#AI_PATROLZONE - EngageZone:__Engage( 1 ) -end - - ---- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To ) - - if Controllable:IsAlive() then - - local EngageRoute = {} - - if self.Controllable:IsNotInZone( self.EngageZone ) then - - -- Find a random 2D point in EngageZone. - local ToEngageZoneVec2 = self.EngageZone:GetRandomVec2() - self:T2( ToEngageZoneVec2 ) - - -- Define Speed and Altitude. - local ToEngageZoneAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) - local ToEngageZoneSpeed = self.PatrolMaxSpeed - self:T2( ToEngageZoneSpeed ) - - -- Obtain a 3D @{Point} from the 2D point + altitude. - local ToEngageZonePointVec3 = POINT_VEC3:New( ToEngageZoneVec2.x, ToEngageZoneAltitude, ToEngageZoneVec2.y ) - - -- Create a route point of type air. - local ToEngageZoneRoutePoint = ToEngageZonePointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToEngageZoneSpeed, - true - ) - - EngageRoute[#EngageRoute+1] = ToEngageZoneRoutePoint - - end - - --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. - - --- Find a random 2D point in EngageZone. - local ToTargetVec2 = self.EngageZone:GetRandomVec2() - self:T2( ToTargetVec2 ) - - --- Define Speed and Altitude. - local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) - local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) - self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) - - --- Obtain a 3D @{Point} from the 2D point + altitude. - local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) - - --- Create a route point of type air. - local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( - POINT_VEC3.RoutePointAltType.BARO, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - ToTargetPointVec3:SmokeRed() - - EngageRoute[#EngageRoute+1] = ToTargetRoutePoint - - - Controllable:OptionROEOpenFire() - Controllable:OptionROTPassiveDefense() - - local AttackTasks = {} - - local DetectedTargets = Controllable:GetDetectedTargets() - for TargetID, Target in pairs( DetectedTargets ) do - local TargetObject = Target.object - self:T( TargetObject ) - if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then - - local TargetUnit = UNIT:Find( TargetObject ) - local TargetUnitName = TargetUnit:GetName() - - if TargetUnit:IsInZone( self.EngageZone ) then - self:E( {"Engaging ", TargetUnit } ) - --local EngageTask = Controllable:EnRouteTaskEngageUnit( TargetUnit, 1 ) - AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( TargetUnit ) - end - - end - end - - EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) - - --- 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 ) - - --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... - self.Controllable:SetState( self.Controllable, "EngageZone", self ) - - self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) - - --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 5 ) - end -end - ---- @param #AI_CAS_ZONE self --- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_CAS_ZONE:onafterDestroy( Controllable, From, Event, To ) - - Controllable:MessageToAll( "Destroyed a target", 15 , "Destroyed!" ) -end - ---- @param #AI_CAS_ZONE self --- @param Core.Event#EVENTDATA EventData -function AI_CAS_ZONE:OnDead( EventData ) - self:T( { "EventDead", EventData } ) - - if EventData.IniDCSUnit then - self:__Destroy( 1, EventData ) - end -end - - ---- (SP) (MP) (FSM) Accept or reject process for player (task) assignments. --- --- === --- --- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ASSIGN state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ASSIGN **Events**: --- --- These are the events defined in this class: --- --- * **Start**: Start the tasking acceptance process. --- * **Assign**: Assign the task. --- * **Reject**: Reject the task.. --- --- ### ACT_ASSIGN **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ASSIGN **States**: --- --- * **UnAssigned**: The player has not accepted the task. --- * **Assigned (*)**: The player has accepted the task. --- * **Rejected (*)**: The player has not accepted the task. --- * **Waiting**: The process is awaiting player feedback. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ASSIGN state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} --- --- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task. --- --- ## 1.1) ACT_ASSIGN_ACCEPT constructor: --- --- * @{#ACT_ASSIGN_ACCEPT.New}(): Creates a new ACT_ASSIGN_ACCEPT object. --- --- === --- --- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN} --- --- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option. --- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task. --- The assignment type also allows to reject the task. --- --- ## 2.1) ACT_ASSIGN_MENU_ACCEPT constructor: --- ----------------------------------------- --- --- * @{#ACT_ASSIGN_MENU_ACCEPT.New}(): Creates a new ACT_ASSIGN_MENU_ACCEPT object. --- --- === --- --- @module Assign - - -do -- ACT_ASSIGN - - --- ACT_ASSIGN class - -- @type ACT_ASSIGN - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends Core.Fsm#FSM_PROCESS - ACT_ASSIGN = { - ClassName = "ACT_ASSIGN", - } - - - --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. - -- @param #ACT_ASSIGN self - -- @return #ACT_ASSIGN The task acceptance process. - function ACT_ASSIGN:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIGN" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "UnAssigned", "Start", "Waiting" ) - self:AddTransition( "Waiting", "Assign", "Assigned" ) - self:AddTransition( "Waiting", "Reject", "Rejected" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:AddEndState( "Assigned" ) - self:AddEndState( "Rejected" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "UnAssigned" ) - - return self - end - -end -- ACT_ASSIGN - - - -do -- ACT_ASSIGN_ACCEPT - - --- ACT_ASSIGN_ACCEPT class - -- @type ACT_ASSIGN_ACCEPT - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIGN - ACT_ASSIGN_ACCEPT = { - ClassName = "ACT_ASSIGN_ACCEPT", - } - - - --- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted. - -- @param #ACT_ASSIGN_ACCEPT self - -- @param #string TaskBriefing - function ACT_ASSIGN_ACCEPT:New( TaskBriefing ) - - local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_ACCEPT - - self.TaskBriefing = TaskBriefing - - return self - end - - function ACT_ASSIGN_ACCEPT:Init( FsmAssign ) - - self.TaskBriefing = FsmAssign.TaskBriefing - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_ACCEPT self - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:__Assign( 1 ) - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_ACCEPT self - -- @param Wrapper.Unit#UNIT ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To ) - env.info( "in here" ) - self:E( { ProcessUnit, From, Event, To } ) - - local ProcessGroup = ProcessUnit:GetGroup() - - self:Message( "You are assigned to the task " .. self.Task:GetName() ) - - self.Task:Assign() - end - -end -- ACT_ASSIGN_ACCEPT - - -do -- ACT_ASSIGN_MENU_ACCEPT - - --- ACT_ASSIGN_MENU_ACCEPT class - -- @type ACT_ASSIGN_MENU_ACCEPT - -- @field Tasking.Task#TASK Task - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIGN - ACT_ASSIGN_MENU_ACCEPT = { - ClassName = "ACT_ASSIGN_MENU_ACCEPT", - } - - --- Init. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName - -- @param #string TaskBriefing - -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing ) - - -- Inherits from BASE - local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT - - self.TaskName = TaskName - self.TaskBriefing = TaskBriefing - - return self - end - - function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign ) - - self.TaskName = FsmAssign.TaskName - self.TaskBriefing = FsmAssign.TaskBriefing - end - - - --- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param #string TaskName - -- @param #string TaskBriefing - -- @return #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing ) - - self.TaskBriefing = TaskBriefing - self.TaskName = TaskName - - return self - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." ) - - local ProcessGroup = ProcessUnit:GetGroup() - - self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" ) - self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self ) - self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self ) - end - - --- Menu function. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuAssign() - self:E( ) - - self:__Assign( 1 ) - end - - --- Menu function. - -- @param #ACT_ASSIGN_MENU_ACCEPT self - function ACT_ASSIGN_MENU_ACCEPT:MenuReject() - self:E( ) - - self:__Reject( 1 ) - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit.UnitNameFrom, Event, To } ) - - self.Menu:Remove() - end - - --- StateMachine callback function - -- @param #ACT_ASSIGN_MENU_ACCEPT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit.UnitName, From, Event, To } ) - - self.Menu:Remove() - --TODO: need to resolve this problem ... it has to do with the events ... - --self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event - ProcessUnit:Destroy() - end - -end -- ACT_ASSIGN_MENU_ACCEPT ---- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. --- --- === --- --- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ROUTE state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ROUTE **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. The process will go into the Report state. --- * **Report**: The process is reporting to the player the route to be followed. --- * **Route**: The process is routing the controllable. --- * **Pause**: The process is pausing the route of the controllable. --- * **Arrive**: The controllable has arrived at a route point. --- * **More**: There are more route points that need to be followed. The process will go back into the Report state. --- * **NoMore**: There are no more route points that need to be followed. The process will go into the Success state. --- --- ### ACT_ROUTE **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ROUTE **States**: --- --- * **None**: The controllable did not receive route commands. --- * **Arrived (*)**: The controllable has arrived at a route point. --- * **Aborted (*)**: The controllable has aborted the route path. --- * **Routing**: The controllable is understay to the route point. --- * **Pausing**: The process is pausing the routing. AI air will go into hover, AI ground will stop moving. Players can fly around. --- * **Success (*)**: All route points were reached. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ROUTE state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE} --- --- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}. --- The player receives on perioding times messages with the coordinates of the route to follow. --- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended. --- --- # 1.1) ACT_ROUTE_ZONE constructor: --- --- * @{#ACT_ROUTE_ZONE.New}(): Creates a new ACT_ROUTE_ZONE object. --- --- === --- --- @module Route - - -do -- ACT_ROUTE - - --- ACT_ROUTE class - -- @type ACT_ROUTE - -- @field Tasking.Task#TASK TASK - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends Core.Fsm#FSM_PROCESS - ACT_ROUTE = { - ClassName = "ACT_ROUTE", - } - - - --- Creates a new routing state machine. The process will route a CLIENT to a ZONE until the CLIENT is within that ZONE. - -- @param #ACT_ROUTE self - -- @return #ACT_ROUTE self - function ACT_ROUTE:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ROUTE" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "None", "Start", "Routing" ) - self:AddTransition( "*", "Report", "Reporting" ) - self:AddTransition( "*", "Route", "Routing" ) - self:AddTransition( "Routing", "Pause", "Pausing" ) - self:AddTransition( "*", "Abort", "Aborted" ) - self:AddTransition( "Routing", "Arrive", "Arrived" ) - self:AddTransition( "Arrived", "Success", "Success" ) - self:AddTransition( "*", "Fail", "Failed" ) - self:AddTransition( "", "", "" ) - self:AddTransition( "", "", "" ) - - self:AddEndState( "Arrived" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "None" ) - - return self - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE:onafterStart( ProcessUnit, From, Event, To ) - - - self:__Route( 1 ) - end - - --- Check if the controllable has arrived. - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @return #boolean - function ACT_ROUTE:onfuncHasArrived( ProcessUnit ) - return false - end - - --- StateMachine callback function - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To ) - self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } ) - - if ProcessUnit:IsAlive() then - self:F( "BeforeRoute 2" ) - local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic - if self.DisplayCount >= self.DisplayInterval then - self:T( { HasArrived = HasArrived } ) - if not HasArrived then - self:Report() - end - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - self:T( { DisplayCount = self.DisplayCount } ) - - if HasArrived then - self:__Arrive( 1 ) - else - self:__Route( 1 ) - end - - return HasArrived -- if false, then the event will not be executed... - end - - return false - - end - -end -- ACT_ROUTE - - - -do -- ACT_ROUTE_ZONE - - --- ACT_ROUTE_ZONE class - -- @type ACT_ROUTE_ZONE - -- @field Tasking.Task#TASK TASK - -- @field Wrapper.Unit#UNIT ProcessUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ROUTE - ACT_ROUTE_ZONE = { - ClassName = "ACT_ROUTE_ZONE", - } - - - --- Creates a new routing state machine. The task will route a controllable to a ZONE until the controllable is within that ZONE. - -- @param #ACT_ROUTE_ZONE self - -- @param Core.Zone#ZONE_BASE TargetZone - function ACT_ROUTE_ZONE:New( TargetZone ) - local self = BASE:Inherit( self, ACT_ROUTE:New() ) -- #ACT_ROUTE_ZONE - - self.TargetZone = TargetZone - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - - return self - end - - function ACT_ROUTE_ZONE:Init( FsmRoute ) - - self.TargetZone = FsmRoute.TargetZone - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - end - - --- Method override to check if the controllable has arrived. - -- @param #ACT_ROUTE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @return #boolean - function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit ) - - if ProcessUnit:IsInZone( self.TargetZone ) then - local RouteText = "You have arrived within the zone." - self:Message( RouteText ) - end - - return ProcessUnit:IsInZone( self.TargetZone ) - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ROUTE_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ROUTE_ZONE:onenterReporting( ProcessUnit, From, Event, To ) - - local ZoneVec2 = self.TargetZone:GetVec2() - local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y ) - local TaskUnitVec2 = ProcessUnit:GetVec2() - local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y ) - local RouteText = "Route to " .. TaskUnitPointVec2:GetBRText( ZonePointVec2 ) .. " km to target." - self:Message( RouteText ) - end - -end -- ACT_ROUTE_ZONE ---- (SP) (MP) (FSM) Account for (Detect, count and report) DCS events occuring on DCS objects (units). --- --- === --- --- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ACCOUNT state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ACCOUNT **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. The process will go into the Report state. --- * **Event**: A relevant event has occured that needs to be accounted for. The process will go into the Account state. --- * **Report**: The process is reporting to the player the accounting status of the DCS events. --- * **More**: There are more DCS events that need to be accounted for. The process will go back into the Report state. --- * **NoMore**: There are no more DCS events that need to be accounted for. The process will go into the Success state. --- --- ### ACT_ACCOUNT **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ACCOUNT **States**: --- --- * **Assigned**: The player is assigned to the task. This is the initialization state for the process. --- * **Waiting**: the process is waiting for a DCS event to occur within the simulator. This state is set automatically. --- * **Report**: The process is Reporting to the players in the group of the unit. This state is set automatically every 30 seconds. --- * **Account**: The relevant DCS event has occurred, and is accounted for. --- * **Success (*)**: All DCS events were accounted for. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ACCOUNT state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- # 1) @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT} --- --- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units. --- The process is given a @{Set} of units that will be tracked upon successful destruction. --- The process will end after each target has been successfully destroyed. --- Each successful dead will trigger an Account state transition that can be scored, modified or administered. --- --- --- ## ACT_ACCOUNT_DEADS constructor: --- --- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object. --- --- === --- --- @module Account - - -do -- ACT_ACCOUNT - - --- ACT_ACCOUNT class - -- @type ACT_ACCOUNT - -- @field Set#SET_UNIT TargetSetUnit - -- @extends Core.Fsm#FSM_PROCESS - ACT_ACCOUNT = { - ClassName = "ACT_ACCOUNT", - TargetSetUnit = nil, - } - - --- Creates a new DESTROY process. - -- @param #ACT_ACCOUNT self - -- @return #ACT_ACCOUNT - function ACT_ACCOUNT:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New() ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "Assigned", "Start", "Waiting") - self:AddTransition( "*", "Wait", "Waiting") - self:AddTransition( "*", "Report", "Report") - self:AddTransition( "*", "Event", "Account") - self:AddTransition( "Account", "More", "Wait") - self:AddTransition( "Account", "NoMore", "Accounted") - self:AddTransition( "*", "Fail", "Failed") - - self:AddEndState( "Accounted" ) - self:AddEndState( "Failed" ) - - self:SetStartState( "Assigned" ) - - return self - end - - --- Process Events - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onafterStart( ProcessUnit, From, Event, To ) - - self:EventOnDead( self.onfuncEventDead ) - - self:__Wait( 1 ) - end - - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onenterWaiting( ProcessUnit, From, Event, To ) - - if self.DisplayCount >= self.DisplayInterval then - self:Report() - self.DisplayCount = 1 - else - self.DisplayCount = self.DisplayCount + 1 - end - - return true -- Process always the event. - end - - --- StateMachine callback function - -- @param #ACT_ACCOUNT self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event ) - - self:__NoMore( 1 ) - end - -end -- ACT_ACCOUNT - -do -- ACT_ACCOUNT_DEADS - - --- ACT_ACCOUNT_DEADS class - -- @type ACT_ACCOUNT_DEADS - -- @field Set#SET_UNIT TargetSetUnit - -- @extends #ACT_ACCOUNT - ACT_ACCOUNT_DEADS = { - ClassName = "ACT_ACCOUNT_DEADS", - TargetSetUnit = nil, - } - - - --- Creates a new DESTROY process. - -- @param #ACT_ACCOUNT_DEADS self - -- @param Set#SET_UNIT TargetSetUnit - -- @param #string TaskName - function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName ) - -- Inherits from BASE - local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS - - self.TargetSetUnit = TargetSetUnit - self.TaskName = TaskName - - self.DisplayInterval = 30 - self.DisplayCount = 30 - self.DisplayMessage = true - self.DisplayTime = 10 -- 10 seconds is the default - self.DisplayCategory = "HQ" -- Targets is the default display category - - return self - end - - function ACT_ACCOUNT_DEADS:Init( FsmAccount ) - - self.TargetSetUnit = FsmAccount.TargetSetUnit - self.TaskName = FsmAccount.TaskName - end - - - - function ACT_ACCOUNT_DEADS:_Destructor() - self:E("_Destructor") - - self:EventRemoveAll() - - end - - --- Process Events - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, From, Event, To ) - self:E( { ProcessUnit, From, Event, To } ) - - self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." ) - end - - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onenterAccount( ProcessUnit, From, Event, To, EventData ) - self:T( { ProcessUnit, EventData, From, Event, To } ) - - self:T({self.Controllable}) - - self.TargetSetUnit:Flush() - - if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then - local TaskGroup = ProcessUnit:GetGroup() - self.TargetSetUnit:RemoveUnitsByName( EventData.IniUnitName ) - self:Message( "You hit a target. Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." ) - end - end - - --- StateMachine callback function - -- @param #ACT_ACCOUNT_DEADS self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, From, Event, To, EventData ) - - if self.TargetSetUnit:Count() > 0 then - self:__More( 1 ) - else - self:__NoMore( 1 ) - end - end - - --- DCS Events - - --- @param #ACT_ACCOUNT_DEADS self - -- @param Event#EVENTDATA EventData - function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData ) - self:T( { "EventDead", EventData } ) - - if EventData.IniDCSUnit then - self:__Event( 1, EventData ) - end - end - -end -- ACT_ACCOUNT DEADS ---- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. --- --- === --- --- # @{#ACT_ASSIST} FSM class, extends @{Core.Fsm#FSM_PROCESS} --- --- ## ACT_ASSIST state machine: --- --- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. --- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below. --- Each derived class follows exactly the same process, using the same events and following the same state transitions, --- but will have **different implementation behaviour** upon each event or state transition. --- --- ### ACT_ASSIST **Events**: --- --- These are the events defined in this class: --- --- * **Start**: The process is started. --- * **Next**: The process is smoking the targets in the given zone. --- --- ### ACT_ASSIST **Event methods**: --- --- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process. --- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine: --- --- * **Immediate**: The event method has exactly the name of the event. --- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed. --- --- ### ACT_ASSIST **States**: --- --- * **None**: The controllable did not receive route commands. --- * **AwaitSmoke (*)**: The process is awaiting to smoke the targets in the zone. --- * **Smoking (*)**: The process is smoking the targets in the zone. --- * **Failed (*)**: The process has failed. --- --- (*) End states of the process. --- --- ### ACT_ASSIST state transition methods: --- --- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. --- There are 2 moments when state transition methods will be called by the state machine: --- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. --- If the state transition method returns false, then the processing of the state transition will not be done! --- If you want to change the behaviour of the AIControllable at this event, return false, --- but then you'll need to specify your own logic using the AIControllable! --- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. --- These state transition methods need to provide a return value, which is specified at the function description. --- --- === --- --- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST} --- --- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}. --- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour. --- At random intervals, a new target is smoked. --- --- # 1.1) ACT_ASSIST_SMOKE_TARGETS_ZONE constructor: --- --- * @{#ACT_ASSIST_SMOKE_TARGETS_ZONE.New}(): Creates a new ACT_ASSIST_SMOKE_TARGETS_ZONE object. --- --- === --- --- @module Smoke - -do -- ACT_ASSIST - - --- ACT_ASSIST class - -- @type ACT_ASSIST - -- @extends Core.Fsm#FSM_PROCESS - ACT_ASSIST = { - ClassName = "ACT_ASSIST", - } - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST self - -- @return #ACT_ASSIST - function ACT_ASSIST:New() - - -- Inherits from BASE - local self = BASE:Inherit( self, FSM_PROCESS:New( "ACT_ASSIST" ) ) -- Core.Fsm#FSM_PROCESS - - self:AddTransition( "None", "Start", "AwaitSmoke" ) - self:AddTransition( "AwaitSmoke", "Next", "Smoking" ) - self:AddTransition( "Smoking", "Next", "AwaitSmoke" ) - self:AddTransition( "*", "Stop", "Success" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:AddEndState( "Failed" ) - self:AddEndState( "Success" ) - - self:SetStartState( "None" ) - - return self - end - - --- Task Events - - --- StateMachine callback function - -- @param #ACT_ASSIST self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIST:onafterStart( ProcessUnit, From, Event, To ) - - local ProcessGroup = ProcessUnit:GetGroup() - local MissionMenu = self:GetMission():GetMissionMenu( ProcessGroup ) - - local function MenuSmoke( MenuParam ) - self:E( MenuParam ) - local self = MenuParam.self - local SmokeColor = MenuParam.SmokeColor - self.SmokeColor = SmokeColor - self:__Next( 1 ) - end - - self.Menu = MENU_GROUP:New( ProcessGroup, "Target acquisition", MissionMenu ) - self.MenuSmokeBlue = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop blue smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Blue } ) - self.MenuSmokeGreen = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop green smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Green } ) - self.MenuSmokeOrange = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Orange smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Orange } ) - self.MenuSmokeRed = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Red smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Red } ) - self.MenuSmokeWhite = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop White smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.White } ) - end - -end - -do -- ACT_ASSIST_SMOKE_TARGETS_ZONE - - --- ACT_ASSIST_SMOKE_TARGETS_ZONE class - -- @type ACT_ASSIST_SMOKE_TARGETS_ZONE - -- @field Set#SET_UNIT TargetSetUnit - -- @field Core.Zone#ZONE_BASE TargetZone - -- @extends #ACT_ASSIST - ACT_ASSIST_SMOKE_TARGETS_ZONE = { - ClassName = "ACT_ASSIST_SMOKE_TARGETS_ZONE", - } - --- function ACT_ASSIST_SMOKE_TARGETS_ZONE:_Destructor() --- self:E("_Destructor") --- --- self.Menu:Remove() --- self:EventRemoveAll() --- end - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit - -- @param Core.Zone#ZONE_BASE TargetZone - function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone ) - local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - return self - end - - function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( FsmSmoke ) - - self.TargetSetUnit = FsmSmoke.TargetSetUnit - self.TargetZone = FsmSmoke.TargetZone - end - - --- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator. - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Set#SET_UNIT TargetSetUnit - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self - function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone ) - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - return self - end - - --- StateMachine callback function - -- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self - -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit - -- @param #string Event - -- @param #string From - -- @param #string To - function ACT_ASSIST_SMOKE_TARGETS_ZONE:onenterSmoking( ProcessUnit, From, Event, To ) - - self.TargetSetUnit:ForEachUnit( - --- @param Wrapper.Unit#UNIT SmokeUnit - function( SmokeUnit ) - if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then - SCHEDULER:New( self, - function() - if SmokeUnit:IsAlive() then - SmokeUnit:Smoke( self.SmokeColor, 150 ) - end - end, {}, math.random( 10, 60 ) - ) - end - end - ) - - end - -end--- A COMMANDCENTER is the owner of multiple missions within MOOSE. --- A COMMANDCENTER governs multiple missions, the tasking and the reporting. --- @module CommandCenter - - - ---- The REPORT class --- @type REPORT --- @extends Core.Base#BASE -REPORT = { - ClassName = "REPORT", -} - ---- Create a new REPORT. --- @param #REPORT self --- @param #string Title --- @return #REPORT -function REPORT:New( Title ) - - local self = BASE:Inherit( self, BASE:New() ) - - self.Report = {} - self.Report[#self.Report+1] = Title - - return self -end - ---- Add a new line to a REPORT. --- @param #REPORT self --- @param #string Text --- @return #REPORT -function REPORT:Add( Text ) - self.Report[#self.Report+1] = Text - return self.Report[#self.Report+1] -end - -function REPORT:Text() - return table.concat( self.Report, "\n" ) -end - ---- The COMMANDCENTER class --- @type COMMANDCENTER --- @field Wrapper.Group#GROUP HQ --- @field Dcs.DCSCoalitionWrapper.Object#coalition CommandCenterCoalition --- @list Missions --- @extends Core.Base#BASE -COMMANDCENTER = { - ClassName = "COMMANDCENTER", - CommandCenterName = "", - CommandCenterCoalition = nil, - CommandCenterPositionable = nil, - Name = "", -} ---- The constructor takes an IDENTIFIABLE as the HQ command center. --- @param #COMMANDCENTER self --- @param Wrapper.Positionable#POSITIONABLE CommandCenterPositionable --- @param #string CommandCenterName --- @return #COMMANDCENTER -function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) - - local self = BASE:Inherit( self, BASE:New() ) - - self.CommandCenterPositionable = CommandCenterPositionable - self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName() - self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition() - - self.Missions = {} - - self:EventOnBirth( - --- @param #COMMANDCENTER self - --- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - self:E( { EventData } ) - local EventGroup = GROUP:Find( EventData.IniDCSGroup ) - if EventGroup and self:HasGroup( EventGroup ) then - local MenuReporting = MENU_GROUP:New( EventGroup, "Reporting", self.CommandCenterMenu ) - local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Summary Report", MenuReporting, self.ReportSummary, self, EventGroup ) - local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Details Report", MenuReporting, self.ReportDetails, self, EventGroup ) - self:ReportSummary( EventGroup ) - end - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:JoinUnit( PlayerUnit ) - Mission:ReportDetails() - end - - end - ) - - -- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do. - -- For these elements, it will= - -- - Set the correct menu. - -- - Assign the PlayerUnit to the Task if required. - -- - Send a message to the other players in the group that this player has joined. - self:EventOnPlayerEnterUnit( - --- @param #COMMANDCENTER self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:JoinUnit( PlayerUnit ) - Mission:ReportDetails() - end - end - ) - - -- Handle when a player leaves a slot and goes back to spectators ... - -- The PlayerUnit will be UnAssigned from the Task. - -- When there is no Unit left running the Task, the Task goes into Abort... - self:EventOnPlayerLeaveUnit( - --- @param #TASK self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - Mission:AbortUnit( PlayerUnit ) - end - end - ) - - -- Handle when a player leaves a slot and goes back to spectators ... - -- The PlayerUnit will be UnAssigned from the Task. - -- When there is no Unit left running the Task, the Task goes into Abort... - self:EventOnCrash( - --- @param #TASK self - -- @param Core.Event#EVENTDATA EventData - function( self, EventData ) - local PlayerUnit = EventData.IniUnit - for MissionID, Mission in pairs( self:GetMissions() ) do - Mission:CrashUnit( PlayerUnit ) - end - end - ) - - return self -end - ---- Gets the name of the HQ command center. --- @param #COMMANDCENTER self --- @return #string -function COMMANDCENTER:GetName() - - return self.CommandCenterName -end - ---- Gets the POSITIONABLE of the HQ command center. --- @param #COMMANDCENTER self --- @return Wrapper.Positionable#POSITIONABLE -function COMMANDCENTER:GetPositionable() - return self.CommandCenterPositionable -end - ---- Get the Missions governed by the HQ command center. --- @param #COMMANDCENTER self --- @return #list -function COMMANDCENTER:GetMissions() - - return self.Missions -end - ---- Add a MISSION to be governed by the HQ command center. --- @param #COMMANDCENTER self --- @param Tasking.Mission#MISSION Mission --- @return Tasking.Mission#MISSION -function COMMANDCENTER:AddMission( Mission ) - - self.Missions[Mission] = Mission - - return Mission -end - ---- Removes a MISSION to be governed by the HQ command center. --- The given Mission is not nilified. --- @param #COMMANDCENTER self --- @param Tasking.Mission#MISSION Mission --- @return Tasking.Mission#MISSION -function COMMANDCENTER:RemoveMission( Mission ) - - self.Missions[Mission] = nil - - return Mission -end - ---- Sets the menu structure of the Missions governed by the HQ command center. --- @param #COMMANDCENTER self -function COMMANDCENTER:SetMenu() - self:F() - - self.CommandCenterMenu = self.CommandCenterMenu or MENU_COALITION:New( self.CommandCenterCoalition, "Command Center (" .. self:GetName() .. ")" ) - - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:RemoveMenu() - end - - for MissionID, Mission in pairs( self:GetMissions() ) do - local Mission = Mission -- Tasking.Mission#MISSION - Mission:SetMenu() - end -end - - ---- Checks of the COMMANDCENTER has a GROUP. --- @param #COMMANDCENTER self --- @param Wrapper.Group#GROUP --- @return #boolean -function COMMANDCENTER:HasGroup( MissionGroup ) - - local Has = false - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - if Mission:HasGroup( MissionGroup ) then - Has = true - break - end - end - - return Has -end - ---- Send a CC message to a GROUP. --- @param #COMMANDCENTER self --- @param #string Message --- @param Wrapper.Group#GROUP TaskGroup --- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. -function COMMANDCENTER:MessageToGroup( Message, TaskGroup, Name ) - - local Prefix = Name and "@ Group (" .. Name .. "): " or '' - Message = Prefix .. Message - self:GetPositionable():MessageToGroup( Message , 20, TaskGroup, self:GetName() ) - -end - ---- Send a CC message to the coalition of the CC. --- @param #COMMANDCENTER self -function COMMANDCENTER:MessageToCoalition( Message ) - - local CCCoalition = self:GetPositionable():GetCoalition() - self:GetPositionable():MessageToBlue( Message , 20, CCCoalition ) - -end - ---- Report the status of all MISSIONs to a GROUP. --- Each Mission is listed, with an indication how many Tasks are still to be completed. --- @param #COMMANDCENTER self -function COMMANDCENTER:ReportSummary( ReportGroup ) - self:E( ReportGroup ) - - local Report = REPORT:New() - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - Report:Add( " - " .. Mission:ReportOverview() ) - end - - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) - -end - ---- Report the status of a Task to a Group. --- Report the details of a Mission, listing the Mission, and all the Task details. --- @param #COMMANDCENTER self -function COMMANDCENTER:ReportDetails( ReportGroup, Task ) - self:E( ReportGroup ) - - local Report = REPORT:New() - - for MissionID, Mission in pairs( self.Missions ) do - local Mission = Mission -- Tasking.Mission#MISSION - Report:Add( " - " .. Mission:ReportDetails() ) - end - - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) -end - ---- A MISSION is the main owner of a Mission orchestration within MOOSE . The Mission framework orchestrates @{CLIENT}s, @{TASK}s, @{STAGE}s etc. --- A @{CLIENT} needs to be registered within the @{MISSION} through the function @{AddClient}. A @{TASK} needs to be registered within the @{MISSION} through the function @{AddTask}. --- @module Mission - ---- The MISSION class --- @type MISSION --- @field #MISSION.Clients _Clients --- @field Core.Menu#MENU_COALITION MissionMenu --- @field #string MissionBriefing --- @extends Core.Fsm#FSM -MISSION = { - ClassName = "MISSION", - Name = "", - MissionStatus = "PENDING", - _Clients = {}, - TaskMenus = {}, - TaskCategoryMenus = {}, - TaskTypeMenus = {}, - _ActiveTasks = {}, - GoalFunction = nil, - MissionReportTrigger = 0, - MissionProgressTrigger = 0, - MissionReportShow = false, - MissionReportFlash = false, - MissionTimeInterval = 0, - MissionCoalition = "", - SUCCESS = 1, - FAILED = 2, - REPEAT = 3, - _GoalTasks = {} -} - ---- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. --- @param #MISSION self --- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter --- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. --- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. --- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. --- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... --- @return #MISSION self -function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition ) - - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM - - self:SetStartState( "Idle" ) - - self:AddTransition( "Idle", "Start", "Ongoing" ) - self:AddTransition( "Ongoing", "Stop", "Idle" ) - self:AddTransition( "Ongoing", "Complete", "Completed" ) - self:AddTransition( "*", "Fail", "Failed" ) - - self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } ) - - self.CommandCenter = CommandCenter - CommandCenter:AddMission( self ) - - self.Name = MissionName - self.MissionPriority = MissionPriority - self.MissionBriefing = MissionBriefing - self.MissionCoalition = MissionCoalition - - self.Tasks = {} - - return self -end - ---- FSM function for a MISSION --- @param #MISSION self --- @param #string Event --- @param #string From --- @param #string To -function MISSION:onbeforeComplete( From, Event, To ) - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if not Task:IsStateSuccess() and not Task:IsStateFailed() and not Task:IsStateAborted() and not Task:IsStateCancelled() then - return false -- Mission cannot be completed. Other Tasks are still active. - end - end - return true -- Allow Mission completion. -end - ---- FSM function for a MISSION --- @param #MISSION self --- @param #string Event --- @param #string From --- @param #string To -function MISSION:onenterCompleted( From, Event, To ) - - self:GetCommandCenter():MessageToCoalition( "Mission " .. self:GetName() .. " has been completed! Good job guys!" ) -end - ---- Gets the mission name. --- @param #MISSION self --- @return #MISSION self -function MISSION:GetName() - return self.Name -end - ---- Add a Unit to join the Mission. --- For each Task within the Mission, the Unit is joined with the Task. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:JoinUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAdded = false - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:JoinUnit( PlayerUnit ) then - PlayerUnitAdded = true - end - end - - return PlayerUnitAdded -end - ---- Aborts a PlayerUnit from the Mission. --- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:AbortUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitRemoved = false - - for TaskID, Task in pairs( self:GetTasks() ) do - if Task:AbortUnit( PlayerUnit ) then - PlayerUnitRemoved = true - end - end - - return PlayerUnitRemoved -end - ---- Handles a crash of a PlayerUnit from the Mission. --- For each Task within the Mission, the PlayerUnit is removed from Task where it is assigned. --- If the Unit was not part of a Task in the Mission, false is returned. --- If the Unit is part of a Task in the Mission, true is returned. --- @param #MISSION self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player crashing. --- @return #boolean true if Unit is part of a Task in the Mission. -function MISSION:CrashUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitRemoved = false - - for TaskID, Task in pairs( self:GetTasks() ) do - if Task:CrashUnit( PlayerUnit ) then - PlayerUnitRemoved = true - end - end - - return PlayerUnitRemoved -end - ---- Add a scoring to the mission. --- @param #MISSION self --- @return #MISSION self -function MISSION:AddScoring( Scoring ) - self.Scoring = Scoring - return self -end - ---- Get the scoring object of a mission. --- @param #MISSION self --- @return #SCORING Scoring -function MISSION:GetScoring() - return self.Scoring -end - ---- Get the groups for which TASKS are given in the mission --- @param #MISSION self --- @return Core.Set#SET_GROUP -function MISSION:GetGroups() - - local SetGroup = SET_GROUP:New() - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - local GroupSet = Task:GetGroups() - GroupSet:ForEachGroup( - function( TaskGroup ) - SetGroup:Add( TaskGroup, TaskGroup ) - end - ) - end - - return SetGroup - -end - - ---- Sets the Planned Task menu. --- @param #MISSION self -function MISSION:SetMenu() - self:F() - - for _, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Task:SetMenu() - end -end - ---- Removes the Planned Task menu. --- @param #MISSION self -function MISSION:RemoveMenu() - self:F() - - for _, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Task:RemoveMenu() - end -end - - ---- Gets the COMMANDCENTER. --- @param #MISSION self --- @return Tasking.CommandCenter#COMMANDCENTER -function MISSION:GetCommandCenter() - return self.CommandCenter -end - ---- Sets the Assigned Task menu. --- @param #MISSION self --- @param Tasking.Task#TASK Task --- @param #string MenuText The menu text. --- @return #MISSION self -function MISSION:SetAssignedMenu( Task ) - - for _, Task in pairs( self.Tasks ) do - local Task = Task -- Tasking.Task#TASK - Task:RemoveMenu() - Task:SetAssignedMenu() - end - -end - ---- Removes a Task menu. --- @param #MISSION self --- @param Tasking.Task#TASK Task --- @return #MISSION self -function MISSION:RemoveTaskMenu( Task ) - - Task:RemoveMenu() -end - - ---- Gets the mission menu for the coalition. --- @param #MISSION self --- @param Wrapper.Group#GROUP TaskGroup --- @return Core.Menu#MENU_COALITION self -function MISSION:GetMissionMenu( TaskGroup ) - - local CommandCenter = self:GetCommandCenter() - local CommandCenterMenu = CommandCenter.CommandCenterMenu - - local MissionName = self:GetName() - - local TaskGroupName = TaskGroup:GetName() - local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ) - - return MissionMenu -end - - ---- Clears the mission menu for the coalition. --- @param #MISSION self --- @return #MISSION self -function MISSION:ClearMissionMenu() - self.MissionMenu:Remove() - self.MissionMenu = nil -end - ---- Get the TASK identified by the TaskNumber from the Mission. This function is useful in GoalFunctions. --- @param #string TaskName The Name of the @{Task} within the @{Mission}. --- @return Tasking.Task#TASK The Task --- @return #nil Returns nil if no task was found. -function MISSION:GetTask( TaskName ) - self:F( { TaskName } ) - - return self.Tasks[TaskName] -end - - ---- Register a @{Task} to be completed within the @{Mission}. --- Note that there can be multiple @{Task}s registered to be completed. --- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return Tasking.Task#TASK The task added. -function MISSION:AddTask( Task ) - - local TaskName = Task:GetTaskName() - self:F( TaskName ) - - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - self.Tasks[TaskName] = Task - - self:GetCommandCenter():SetMenu() - - return Task -end - ---- Removes a @{Task} to be completed within the @{Mission}. --- Note that there can be multiple @{Task}s registered to be completed. --- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return #nil The cleaned Task reference. -function MISSION:RemoveTask( Task ) - - local TaskName = Task:GetTaskName() - - self:F( TaskName ) - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - -- Ensure everything gets garbarge collected. - self.Tasks[TaskName] = nil - Task = nil - - collectgarbage() - - self:GetCommandCenter():SetMenu() - - return nil -end - ---- Return the next @{Task} ID to be completed within the @{Mission}. --- @param #MISSION self --- @param Tasking.Task#TASK Task is the @{Task} object. --- @return Tasking.Task#TASK The task added. -function MISSION:GetNextTaskID( Task ) - - local TaskName = Task:GetTaskName() - self:F( TaskName ) - self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 } - - self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1 - - return self.Tasks[TaskName].n -end - - - ---- old stuff - ---- Returns if a Mission has completed. --- @return bool -function MISSION:IsCompleted() - self:F() - return self.MissionStatus == "ACCOMPLISHED" -end - ---- Set a Mission to completed. -function MISSION:Completed() - self:F() - self.MissionStatus = "ACCOMPLISHED" - self:StatusToClients() -end - ---- Returns if a Mission is ongoing. --- treturn bool -function MISSION:IsOngoing() - self:F() - return self.MissionStatus == "ONGOING" -end - ---- Set a Mission to ongoing. -function MISSION:Ongoing() - self:F() - self.MissionStatus = "ONGOING" - --self:StatusToClients() -end - ---- Returns if a Mission is pending. --- treturn bool -function MISSION:IsPending() - self:F() - return self.MissionStatus == "PENDING" -end - ---- Set a Mission to pending. -function MISSION:Pending() - self:F() - self.MissionStatus = "PENDING" - self:StatusToClients() -end - ---- Returns if a Mission has failed. --- treturn bool -function MISSION:IsFailed() - self:F() - return self.MissionStatus == "FAILED" -end - ---- Set a Mission to failed. -function MISSION:Failed() - self:F() - self.MissionStatus = "FAILED" - self:StatusToClients() -end - ---- Send the status of the MISSION to all Clients. -function MISSION:StatusToClients() - self:F() - if self.MissionReportFlash then - for ClientID, Client in pairs( self._Clients ) do - Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, "Mission Command: Mission Status") - end - end -end - -function MISSION:HasGroup( TaskGroup ) - local Has = false - - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:HasGroup( TaskGroup ) then - Has = true - break - end - end - - return Has -end - ---- Create a summary report of the Mission (one line). --- @param #MISSION self --- @return #string -function MISSION:ReportSummary() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - if Task:IsStateSuccess() or Task:IsStateFailed() then - else - TasksRemaining = TasksRemaining + 1 - end - end - - Report:Add( "Mission " .. Name .. " - " .. Status .. " - " .. TasksRemaining .. " tasks remaining." ) - - return Report:Text() -end - ---- Create a overview report of the Mission (multiple lines). --- @param #MISSION self --- @return #string -function MISSION:ReportOverview() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Report:Add( "- " .. Task:ReportSummary() ) - end - - return Report:Text() -end - ---- Create a detailed report of the Mission, listing all the details of the Task. --- @param #MISSION self --- @return #string -function MISSION:ReportDetails() - - local Report = REPORT:New() - - -- List the name of the mission. - local Name = self:GetName() - - -- Determine the status of the mission. - local Status = self:GetState() - - Report:Add( "Mission " .. Name .. " - State '" .. Status .. "'" ) - - -- Determine how many tasks are remaining. - local TasksRemaining = 0 - for TaskID, Task in pairs( self:GetTasks() ) do - local Task = Task -- Tasking.Task#TASK - Report:Add( Task:ReportDetails() ) - end - - return Report:Text() -end - ---- Report the status of all MISSIONs to all active Clients. -function MISSION:ReportToAll() - self:F() - - local AlivePlayers = '' - for ClientID, Client in pairs( self._Clients ) do - if Client:GetDCSGroup() then - if Client:GetClientGroupDCSUnit() then - if Client:GetClientGroupDCSUnit():getLife() > 0.0 then - if AlivePlayers == '' then - AlivePlayers = ' Players: ' .. Client:GetClientGroupDCSUnit():getPlayerName() - else - AlivePlayers = AlivePlayers .. ' / ' .. Client:GetClientGroupDCSUnit():getPlayerName() - end - end - end - end - end - local Tasks = self:GetTasks() - local TaskText = "" - for TaskID, TaskData in pairs( Tasks ) do - TaskText = TaskText .. " - Task " .. TaskID .. ": " .. TaskData.Name .. ": " .. TaskData:GetGoalProgress() .. "\n" - end - MESSAGE:New( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. ' ( ' .. self.MissionPriority .. ' mission )' .. AlivePlayers .. "\n" .. TaskText:gsub("\n$",""), 10, "Mission Command: Mission Report" ):ToAll() -end - - ---- Add a goal function to a MISSION. Goal functions are called when a @{TASK} within a mission has been completed. --- @param function GoalFunction is the function defined by the mission designer to evaluate whether a certain goal has been reached after a @{TASK} finishes within the @{MISSION}. A GoalFunction must accept 2 parameters: Mission, Client, which contains the current MISSION object and the current CLIENT object respectively. --- @usage --- PatriotActivation = { --- { "US SAM Patriot Zerti", false }, --- { "US SAM Patriot Zegduleti", false }, --- { "US SAM Patriot Gvleti", false } --- } --- --- function DeployPatriotTroopsGoal( Mission, Client ) --- --- --- -- Check if the cargo is all deployed for mission success. --- for CargoID, CargoData in pairs( Mission._Cargos ) do --- if Group.getByName( CargoData.CargoGroupName ) then --- CargoGroup = Group.getByName( CargoData.CargoGroupName ) --- if CargoGroup then --- -- Check if the cargo is ready to activate --- CurrentLandingZoneID = routines.IsUnitInZones( CargoGroup:getUnits()[1], Mission:GetTask( 2 ).LandingZones ) -- The second task is the Deploytask to measure mission success upon --- if CurrentLandingZoneID then --- if PatriotActivation[CurrentLandingZoneID][2] == false then --- -- Now check if this is a new Mission Task to be completed... --- trigger.action.setGroupAIOn( Group.getByName( PatriotActivation[CurrentLandingZoneID][1] ) ) --- PatriotActivation[CurrentLandingZoneID][2] = true --- MessageToBlue( "Mission Command: Message to all airborne units! The " .. PatriotActivation[CurrentLandingZoneID][1] .. " is armed. Our air defenses are now stronger.", 60, "BLUE/PatriotDefense" ) --- MessageToRed( "Mission Command: Our satellite systems are detecting additional NATO air defenses. To all airborne units: Take care!!!", 60, "RED/PatriotDefense" ) --- Mission:GetTask( 2 ):AddGoalCompletion( "Patriots activated", PatriotActivation[CurrentLandingZoneID][1], 1 ) -- Register Patriot activation as part of mission goal. --- end --- end --- end --- end --- end --- end --- --- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' ) --- Mission:AddGoalFunction( DeployPatriotTroopsGoal ) -function MISSION:AddGoalFunction( GoalFunction ) - self:F() - self.GoalFunction = GoalFunction -end - ---- Register a new @{CLIENT} to participate within the mission. --- @param CLIENT Client is the @{CLIENT} object. The object must have been instantiated with @{CLIENT:New}. --- @return CLIENT --- @usage --- Add a number of Client objects to the Mission. --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*HOT-Deploy Troops 1', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*RAMP-Deploy Troops 3', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*HOT-Deploy Troops 2', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) --- Mission:AddClient( CLIENT:FindByName( 'US UH-1H*RAMP-Deploy Troops 4', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() ) -function MISSION:AddClient( Client ) - self:F( { Client } ) - - local Valid = true - - if Valid then - self._Clients[Client.ClientName] = Client - end - - return Client -end - ---- Find a @{CLIENT} object within the @{MISSION} by its ClientName. --- @param CLIENT ClientName is a string defining the Client Group as defined within the ME. --- @return CLIENT --- @usage --- -- Seach for Client "Bomber" within the Mission. --- local BomberClient = Mission:FindClient( "Bomber" ) -function MISSION:FindClient( ClientName ) - self:F( { self._Clients[ClientName] } ) - return self._Clients[ClientName] -end - - ---- Get all the TASKs from the Mission. This function is useful in GoalFunctions. --- @return {TASK,...} Structure of TASKS with the @{TASK} number as the key. --- @usage --- -- Get Tasks from the Mission. --- Tasks = Mission:GetTasks() --- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) -function MISSION:GetTasks() - self:F() - - return self.Tasks -end - - ---[[ - _TransportExecuteStage: Defines the different stages of Transport unload/load execution. This table is internal and is used to control the validity of Transport load/unload timing. - - - _TransportExecuteStage.EXECUTING - - _TransportExecuteStage.SUCCESS - - _TransportExecuteStage.FAILED - ---]] -_TransportExecuteStage = { - NONE = 0, - EXECUTING = 1, - SUCCESS = 2, - FAILED = 3 -} - - ---- The MISSIONSCHEDULER is an OBJECT and is the main scheduler of ALL active MISSIONs registered within this scheduler. It's workings are considered internal and is automatically created when the Mission.lua file is included. --- @type MISSIONSCHEDULER --- @field #MISSIONSCHEDULER.MISSIONS Missions -MISSIONSCHEDULER = { - Missions = {}, - MissionCount = 0, - TimeIntervalCount = 0, - TimeIntervalShow = 150, - TimeSeconds = 14400, - TimeShow = 5 -} - ---- @type MISSIONSCHEDULER.MISSIONS --- @list <#MISSION> Mission - ---- This is the main MISSIONSCHEDULER Scheduler function. It is considered internal and is automatically created when the Mission.lua file is included. -function MISSIONSCHEDULER.Scheduler() - - - -- loop through the missions in the TransportTasks - for MissionName, MissionData in pairs( MISSIONSCHEDULER.Missions ) do - - local Mission = MissionData -- #MISSION - - if not Mission:IsCompleted() then - - -- This flag will monitor if for this mission, there are clients alive. If this flag is still false at the end of the loop, the mission status will be set to Pending (if not Failed or Completed). - local ClientsAlive = false - - for ClientID, ClientData in pairs( Mission._Clients ) do - - local Client = ClientData -- Wrapper.Client#CLIENT - - if Client:IsAlive() then - - -- There is at least one Client that is alive... So the Mission status is set to Ongoing. - ClientsAlive = true - - -- If this Client was not registered as Alive before: - -- 1. We register the Client as Alive. - -- 2. We initialize the Client Tasks and make a link to the original Mission Task. - -- 3. We initialize the Cargos. - -- 4. We flag the Mission as Ongoing. - if not Client.ClientAlive then - Client.ClientAlive = true - Client.ClientBriefingShown = false - for TaskNumber, Task in pairs( Mission._Tasks ) do - -- Note that this a deepCopy. Each client must have their own Tasks with own Stages!!! - Client._Tasks[TaskNumber] = routines.utils.deepCopy( Mission._Tasks[TaskNumber] ) - -- Each MissionTask must point to the original Mission. - Client._Tasks[TaskNumber].MissionTask = Mission._Tasks[TaskNumber] - Client._Tasks[TaskNumber].Cargos = Mission._Tasks[TaskNumber].Cargos - Client._Tasks[TaskNumber].LandingZones = Mission._Tasks[TaskNumber].LandingZones - end - - Mission:Ongoing() - end - - - -- For each Client, check for each Task the state and evolve the mission. - -- This flag will indicate if the Task of the Client is Complete. - local TaskComplete = false - - for TaskNumber, Task in pairs( Client._Tasks ) do - - if not Task.Stage then - Task:SetStage( 1 ) - end - - - local TransportTime = timer.getTime() - - if not Task:IsDone() then - - if Task:Goal() then - Task:ShowGoalProgress( Mission, Client ) - end - - --env.info( 'Scheduler: Mission = ' .. Mission.Name .. ' / Client = ' .. Client.ClientName .. ' / Task = ' .. Task.Name .. ' / Stage = ' .. Task.ActiveStage .. ' - ' .. Task.Stage.Name .. ' - ' .. Task.Stage.StageType ) - - -- Action - if Task:StageExecute() then - Task.Stage:Execute( Mission, Client, Task ) - end - - -- Wait until execution is finished - if Task.ExecuteStage == _TransportExecuteStage.EXECUTING then - Task.Stage:Executing( Mission, Client, Task ) - end - - -- Validate completion or reverse to earlier stage - if Task.Time + Task.Stage.WaitTime <= TransportTime then - Task:SetStage( Task.Stage:Validate( Mission, Client, Task ) ) - end - - if Task:IsDone() then - --env.info( 'Scheduler: Mission '.. Mission.Name .. ' Task ' .. Task.Name .. ' Stage ' .. Task.Stage.Name .. ' done. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) ) - TaskComplete = true -- when a task is not yet completed, a mission cannot be completed - - else - -- break only if this task is not yet done, so that future task are not yet activated. - TaskComplete = false -- when a task is not yet completed, a mission cannot be completed - --env.info( 'Scheduler: Mission "'.. Mission.Name .. '" Task "' .. Task.Name .. '" Stage "' .. Task.Stage.Name .. '" break. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) ) - break - end - - if TaskComplete then - - if Mission.GoalFunction ~= nil then - Mission.GoalFunction( Mission, Client ) - end - if MISSIONSCHEDULER.Scoring then - MISSIONSCHEDULER.Scoring:_AddMissionTaskScore( Client:GetClientGroupDCSUnit(), Mission.Name, 25 ) - end - --- if not Mission:IsCompleted() then --- end - end - end - end - - local MissionComplete = true - for TaskNumber, Task in pairs( Mission._Tasks ) do - if Task:Goal() then --- Task:ShowGoalProgress( Mission, Client ) - if Task:IsGoalReached() then - else - MissionComplete = false - end - else - MissionComplete = false -- If there is no goal, the mission should never be ended. The goal status will be set somewhere else. - end - end - - if MissionComplete then - Mission:Completed() - if MISSIONSCHEDULER.Scoring then - MISSIONSCHEDULER.Scoring:_AddMissionScore( Mission.Name, 100 ) - end - else - if TaskComplete then - -- Reset for new tasking of active client - Client.ClientAlive = false -- Reset the client tasks. - end - end - - - else - if Client.ClientAlive then - env.info( 'Scheduler: Client "' .. Client.ClientName .. '" is inactive.' ) - Client.ClientAlive = false - - -- This is tricky. If we sanitize Client._Tasks before sanitizing Client._Tasks[TaskNumber].MissionTask, then the original MissionTask will be sanitized, and will be lost within the garbage collector. - -- So first sanitize Client._Tasks[TaskNumber].MissionTask, after that, sanitize only the whole _Tasks structure... - --Client._Tasks[TaskNumber].MissionTask = nil - --Client._Tasks = nil - end - end - end - - -- If all Clients of this Mission are not activated, then the Mission status needs to be put back into Pending status. - -- But only if the Mission was Ongoing. In case the Mission is Completed or Failed, the Mission status may not be changed. In these cases, this will be the last run of this Mission in the Scheduler. - if ClientsAlive == false then - if Mission:IsOngoing() then - -- Mission status back to pending... - Mission:Pending() - end - end - end - - Mission:StatusToClients() - - if Mission:ReportTrigger() then - Mission:ReportToAll() - end - end - - return true -end - ---- Start the MISSIONSCHEDULER. -function MISSIONSCHEDULER.Start() - if MISSIONSCHEDULER ~= nil then - --MISSIONSCHEDULER.SchedulerId = routines.scheduleFunction( MISSIONSCHEDULER.Scheduler, { }, 0, 2 ) - MISSIONSCHEDULER.SchedulerId = SCHEDULER:New( nil, MISSIONSCHEDULER.Scheduler, { }, 0, 2 ) - end -end - ---- Stop the MISSIONSCHEDULER. -function MISSIONSCHEDULER.Stop() - if MISSIONSCHEDULER.SchedulerId then - routines.removeFunction(MISSIONSCHEDULER.SchedulerId) - MISSIONSCHEDULER.SchedulerId = nil - end -end - ---- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. --- @param Mission is the MISSION object instantiated by @{MISSION:New}. --- @return MISSION --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) -function MISSIONSCHEDULER.AddMission( Mission ) - MISSIONSCHEDULER.Missions[Mission.Name] = Mission - MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount + 1 - -- Add an overall AI Client for the AI tasks... This AI Client will facilitate the Events in the background for each Task. - --MissionAdd:AddClient( CLIENT:Register( 'AI' ) ) - - return Mission -end - ---- Remove a MISSION from the MISSIONSCHEDULER. --- @param MissionName is the name of the MISSION given at declaration using @{AddMission}. --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) --- --- -- Now remove the Mission. --- MISSIONSCHEDULER:RemoveMission( 'Russia Transport Troops SA-6' ) -function MISSIONSCHEDULER.RemoveMission( MissionName ) - MISSIONSCHEDULER.Missions[MissionName] = nil - MISSIONSCHEDULER.MissionCount = MISSIONSCHEDULER.MissionCount - 1 -end - ---- Find a MISSION within the MISSIONSCHEDULER. --- @param MissionName is the name of the MISSION given at declaration using @{AddMission}. --- @return MISSION --- @usage --- -- Declare a mission. --- Mission = MISSION:New( 'Russia Transport Troops SA-6', --- 'Operational', --- 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', --- 'Russia' ) --- MISSIONSCHEDULER:AddMission( Mission ) --- --- -- Now find the Mission. --- MissionFind = MISSIONSCHEDULER:FindMission( 'Russia Transport Troops SA-6' ) -function MISSIONSCHEDULER.FindMission( MissionName ) - return MISSIONSCHEDULER.Missions[MissionName] -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsShow( ) - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = true - Mission.MissionReportFlash = false - end -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsFlash( TimeInterval ) - local Count = 0 - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = false - Mission.MissionReportFlash = true - Mission.MissionReportTrigger = timer.getTime() + Count * TimeInterval - Mission.MissionTimeInterval = MISSIONSCHEDULER.MissionCount * TimeInterval - env.info( "TimeInterval = " .. Mission.MissionTimeInterval ) - Count = Count + 1 - end -end - --- Internal function used by the MISSIONSCHEDULER menu. -function MISSIONSCHEDULER.ReportMissionsHide( Prm ) - for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do - Mission.MissionReportShow = false - Mission.MissionReportFlash = false - end -end - ---- Enables a MENU option in the communications menu under F10 to control the status of the active missions. --- This function should be called only once when starting the MISSIONSCHEDULER. -function MISSIONSCHEDULER.ReportMenu() - local ReportMenu = SUBMENU:New( 'Status' ) - local ReportMenuShow = COMMANDMENU:New( 'Show Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsShow, 0 ) - local ReportMenuFlash = COMMANDMENU:New('Flash Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsFlash, 120 ) - local ReportMenuHide = COMMANDMENU:New( 'Hide Report Missions', ReportMenu, MISSIONSCHEDULER.ReportMissionsHide, 0 ) -end - ---- Show the remaining mission time. -function MISSIONSCHEDULER:TimeShow() - self.TimeIntervalCount = self.TimeIntervalCount + 1 - if self.TimeIntervalCount >= self.TimeTriggerShow then - local TimeMsg = string.format("%00d", ( self.TimeSeconds / 60 ) - ( timer.getTime() / 60 )) .. ' minutes left until mission reload.' - MESSAGE:New( TimeMsg, self.TimeShow, "Mission time" ):ToAll() - self.TimeIntervalCount = 0 - end -end - -function MISSIONSCHEDULER:Time( TimeSeconds, TimeIntervalShow, TimeShow ) - - self.TimeIntervalCount = 0 - self.TimeSeconds = TimeSeconds - self.TimeIntervalShow = TimeIntervalShow - self.TimeShow = TimeShow -end - ---- Adds a mission scoring to the game. -function MISSIONSCHEDULER:Scoring( Scoring ) - - self.Scoring = Scoring -end - ---- This module contains the TASK class. --- --- 1) @{#TASK} class, extends @{Core.Base#BASE} --- ============================================ --- 1.1) The @{#TASK} class implements the methods for task orchestration within MOOSE. --- ---------------------------------------------------------------------------------------- --- The class provides a couple of methods to: --- --- * @{#TASK.AssignToGroup}():Assign a task to a group (of players). --- * @{#TASK.AddProcess}():Add a @{Process} to a task. --- * @{#TASK.RemoveProcesses}():Remove a running @{Process} from a running task. --- * @{#TASK.SetStateMachine}():Set a @{Fsm} to a task. --- * @{#TASK.RemoveStateMachine}():Remove @{Fsm} from a task. --- * @{#TASK.HasStateMachine}():Enquire if the task has a @{Fsm} --- * @{#TASK.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK}. --- * @{#TASK.UnAssignFromUnit}(): Unassign the task from a unit. --- --- 1.2) Set and enquire task status (beyond the task state machine processing). --- ---------------------------------------------------------------------------- --- A task needs to implement as a minimum the following task states: --- --- * **Success**: Expresses the successful execution and finalization of the task. --- * **Failed**: Expresses the failure of a task. --- * **Planned**: Expresses that the task is created, but not yet in execution and is not assigned yet. --- * **Assigned**: Expresses that the task is assigned to a Group of players, and that the task is in execution mode. --- --- A task may also implement the following task states: --- --- * **Rejected**: Expresses that the task is rejected by a player, who was requested to accept the task. --- * **Cancelled**: Expresses that the task is cancelled by HQ or through a logical situation where a cancellation of the task is required. --- --- A task can implement more statusses than the ones outlined above. Please consult the documentation of the specific tasks to understand the different status modelled. --- --- The status of tasks can be set by the methods **State** followed by the task status. An example is `StateAssigned()`. --- The status of tasks can be enquired by the methods **IsState** followed by the task status name. An example is `if IsStateAssigned() then`. --- --- 1.3) Add scoring when reaching a certain task status: --- ----------------------------------------------------- --- Upon reaching a certain task status in a task, additional scoring can be given. If the Mission has a scoring system attached, the scores will be added to the mission scoring. --- Use the method @{#TASK.AddScore}() to add scores when a status is reached. --- --- 1.4) Task briefing: --- ------------------- --- A task briefing can be given that is shown to the player when he is assigned to the task. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task - ---- The TASK class --- @type TASK --- @field Core.Scheduler#SCHEDULER TaskScheduler --- @field Tasking.Mission#MISSION Mission --- @field Core.Set#SET_GROUP SetGroup The Set of Groups assigned to the Task --- @field Core.Fsm#FSM_PROCESS FsmTemplate --- @field Tasking.Mission#MISSION Mission --- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter --- @extends Core.Fsm#FSM_TASK -TASK = { - ClassName = "TASK", - TaskScheduler = nil, - ProcessClasses = {}, -- The container of the Process classes that will be used to create and assign new processes for the task to ProcessUnits. - Processes = {}, -- The container of actual process objects instantiated and assigned to ProcessUnits. - Players = nil, - Scores = {}, - Menu = {}, - SetGroup = nil, - FsmTemplate = nil, - Mission = nil, - CommandCenter = nil, -} - ---- FSM PlayerAborted event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerAborted --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he went back to spectators or left the mission. --- @param #string PlayerName The name of the Player. - ---- FSM PlayerCrashed event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerCrashed --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he crashed in the mission. --- @param #string PlayerName The name of the Player. - ---- FSM PlayerDead event handler prototype for TASK. --- @function [parent=#TASK] OnAfterPlayerDead --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The Unit of the Player when he died in the mission. --- @param #string PlayerName The name of the Player. - ---- FSM Fail synchronous event function for TASK. --- Use this event to Fail the Task. --- @function [parent=#TASK] Fail --- @param #TASK self - ---- FSM Fail asynchronous event function for TASK. --- Use this event to Fail the Task. --- @function [parent=#TASK] __Fail --- @param #TASK self - ---- FSM Abort synchronous event function for TASK. --- Use this event to Abort the Task. --- @function [parent=#TASK] Abort --- @param #TASK self - ---- FSM Abort asynchronous event function for TASK. --- Use this event to Abort the Task. --- @function [parent=#TASK] __Abort --- @param #TASK self - ---- FSM Success synchronous event function for TASK. --- Use this event to make the Task a Success. --- @function [parent=#TASK] Success --- @param #TASK self - ---- FSM Success asynchronous event function for TASK. --- Use this event to make the Task a Success. --- @function [parent=#TASK] __Success --- @param #TASK self - ---- FSM Cancel synchronous event function for TASK. --- Use this event to Cancel the Task. --- @function [parent=#TASK] Cancel --- @param #TASK self - ---- FSM Cancel asynchronous event function for TASK. --- Use this event to Cancel the Task. --- @function [parent=#TASK] __Cancel --- @param #TASK self - ---- FSM Replan synchronous event function for TASK. --- Use this event to Replan the Task. --- @function [parent=#TASK] Replan --- @param #TASK self - ---- FSM Replan asynchronous event function for TASK. --- Use this event to Replan the Task. --- @function [parent=#TASK] __Replan --- @param #TASK self - - ---- Instantiates a new TASK. Should never be used. Interface Class. --- @param #TASK self --- @param Tasking.Mission#MISSION Mission The mission wherein the Task is registered. --- @param Core.Set#SET_GROUP SetGroupAssign The set of groups for which the Task can be assigned. --- @param #string TaskName The name of the Task --- @param #string TaskType The type of the Task --- @return #TASK self -function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) - - local self = BASE:Inherit( self, FSM_TASK:New() ) -- Core.Fsm#FSM_TASK - - self:SetStartState( "Planned" ) - self:AddTransition( "Planned", "Assign", "Assigned" ) - self:AddTransition( "Assigned", "AssignUnit", "Assigned" ) - self:AddTransition( "Assigned", "Success", "Success" ) - self:AddTransition( "Assigned", "Fail", "Failed" ) - self:AddTransition( "Assigned", "Abort", "Aborted" ) - self:AddTransition( "Assigned", "Cancel", "Cancelled" ) - self:AddTransition( "*", "PlayerCrashed", "*" ) - self:AddTransition( "*", "PlayerAborted", "*" ) - self:AddTransition( "*", "PlayerDead", "*" ) - self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" ) - - self:E( "New TASK " .. TaskName ) - - self.Processes = {} - self.Fsm = {} - - self.Mission = Mission - self.CommandCenter = Mission:GetCommandCenter() - - self.SetGroup = SetGroupAssign - - self:SetType( TaskType ) - self:SetName( TaskName ) - self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences .. - - self.TaskBriefing = "You are invited for the task: " .. self.TaskName .. "." - - self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() - - -- Handle the birth of new planes within the assigned set. - - - -- Handle when a player crashes ... - -- The Task is UnAssigned from the Unit. - -- When there is no Unit left running the Task, and all of the Players crashed, the Task goes into Failed ... --- self:EventOnCrash( --- --- @param #TASK self --- -- @param Core.Event#EVENTDATA EventData --- function( self, EventData ) --- self:E( "In LeaveUnit" ) --- self:E( { "State", self:GetState() } ) --- if self:IsStateAssigned() then --- local TaskUnit = EventData.IniUnit --- local TaskGroup = EventData.IniUnit:GetGroup() --- self:E( self.SetGroup:IsIncludeObject( TaskGroup ) ) --- if self.SetGroup:IsIncludeObject( TaskGroup ) then --- self:UnAssignFromUnit( TaskUnit ) --- end --- self:MessageToGroups( TaskUnit:GetPlayerName() .. " crashed!, and has aborted Task " .. self:GetName() ) --- end --- end --- ) --- - - Mission:AddTask( self ) - - return self -end - ---- Get the Task FSM Process Template --- @param #TASK self --- @return Core.Fsm#FSM_PROCESS -function TASK:GetUnitProcess() - - return self.FsmTemplate -end - ---- Sets the Task FSM Process Template --- @param #TASK self --- @param Core.Fsm#FSM_PROCESS -function TASK:SetUnitProcess( FsmTemplate ) - - self.FsmTemplate = FsmTemplate -end - ---- Add a PlayerUnit to join the Task. --- For each Group within the Task, the Unit is check if it can join the Task. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player joining the Mission. --- @return #boolean true if Unit is part of the Task. -function TASK:JoinUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAdded = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task. - -- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader. - if self:IsStatePlanned() or self:IsStateReplanned() then - self:SetMenuForGroup( PlayerGroup ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() ) - end - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:AssignToUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " joined Task " .. self:GetName() ) - end - end - end - - return PlayerUnitAdded -end - ---- Abort a PlayerUnit from a Task. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. -function TASK:AbortUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitAborted = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. - -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:UnAssignFromUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " aborted Task " .. self:GetName() ) - self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) - if #PlayerGroup:GetUnits() == 1 then - PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) - self:RemoveMenuForGroup( PlayerGroup ) - end - self:PlayerAborted( PlayerUnit ) - end - end - end - - return PlayerUnitAborted -end - ---- A PlayerUnit crashed in a Task. Abort the Player. --- If the Unit was not part of the Task, false is returned. --- If the Unit is part of the Task, true is returned. --- @param #TASK self --- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. -function TASK:CrashUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitCrashed = false - - local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() - - -- Is the PlayerGroup part of the PlayerGroups? - if PlayerGroups:IsIncludeObject( PlayerGroup ) then - - -- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is aborted from the Task. - -- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group. - if self:IsStateAssigned() then - local IsAssignedToGroup = self:IsAssignedToGroup( PlayerGroup ) - self:E( { IsAssignedToGroup = IsAssignedToGroup } ) - if IsAssignedToGroup then - self:UnAssignFromUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " crashed in Task " .. self:GetName() ) - self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) - if #PlayerGroup:GetUnits() == 1 then - PlayerGroup:SetState( PlayerGroup, "Assigned", nil ) - self:RemoveMenuForGroup( PlayerGroup ) - end - self:PlayerCrashed( PlayerUnit ) - end - end - end - - return PlayerUnitCrashed -end - - - ---- Gets the Mission to where the TASK belongs. --- @param #TASK self --- @return Tasking.Mission#MISSION -function TASK:GetMission() - - return self.Mission -end - - ---- Gets the SET_GROUP assigned to the TASK. --- @param #TASK self --- @return Core.Set#SET_GROUP -function TASK:GetGroups() - return self.SetGroup -end - - - ---- Assign the @{Task}to a @{Group}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK -function TASK:AssignToGroup( TaskGroup ) - self:F2( TaskGroup:GetName() ) - - local TaskGroupName = TaskGroup:GetName() - - TaskGroup:SetState( TaskGroup, "Assigned", self ) - - self:RemoveMenuForGroup( TaskGroup ) - self:SetAssignedMenuForGroup( TaskGroup ) - - local TaskUnits = TaskGroup:GetUnits() - for UnitID, UnitData in pairs( TaskUnits ) do - local TaskUnit = UnitData -- Wrapper.Unit#UNIT - local PlayerName = TaskUnit:GetPlayerName() - self:E(PlayerName) - if PlayerName ~= nil or PlayerName ~= "" then - self:AssignToUnit( TaskUnit ) - end - end - - return self -end - ---- --- @param #TASK self --- @param Wrapper.Group#GROUP FindGroup --- @return #boolean -function TASK:HasGroup( FindGroup ) - - self:GetGroups():FilterOnce() -- Ensure that the filter is updated. - return self:GetGroups():IsIncludeObject( FindGroup ) - -end - ---- Assign the @{Task} to an alive @{Unit}. --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:AssignToUnit( TaskUnit ) - self:F( TaskUnit:GetName() ) - - local FsmTemplate = self:GetUnitProcess() - - -- Assign a new FsmUnit to TaskUnit. - local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Core.Fsm#FSM_PROCESS - self:E({"Address FsmUnit", tostring( FsmUnit ) } ) - - FsmUnit:SetStartState( "Planned" ) - FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow. - - return self -end - ---- UnAssign the @{Task} from an alive @{Unit}. --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:UnAssignFromUnit( TaskUnit ) - self:F( TaskUnit ) - - self:RemoveStateMachine( TaskUnit ) - - return self -end - ---- Send a message of the @{Task} to the assigned @{Group}s. --- @param #TASK self -function TASK:MessageToGroups( Message ) - self:F( { Message = Message } ) - - local Mission = self:GetMission() - local CC = Mission:GetCommandCenter() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - local TaskGroup = TaskGroup -- Wrapper.Group#GROUP - CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() ) - end -end - - ---- Send the briefng message of the @{Task} to the assigned @{Group}s. --- @param #TASK self -function TASK:SendBriefingToAssignedGroups() - self:F2() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - - if self:IsAssignedToGroup( TaskGroup ) then - TaskGroup:Message( self.TaskBriefing, 60 ) - end - end -end - - ---- Assign the @{Task} from the @{Group}s. --- @param #TASK self -function TASK:UnAssignFromGroups() - self:F2() - - for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - - TaskGroup:SetState( TaskGroup, "Assigned", nil ) - - self:RemoveMenuForGroup( TaskGroup ) - - local TaskUnits = TaskGroup:GetUnits() - for UnitID, UnitData in pairs( TaskUnits ) do - local TaskUnit = UnitData -- Wrapper.Unit#UNIT - local PlayerName = TaskUnit:GetPlayerName() - if PlayerName ~= nil or PlayerName ~= "" then - self:UnAssignFromUnit( TaskUnit ) - end - end - end -end - ---- Returns if the @{Task} is assigned to the Group. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #boolean -function TASK:IsAssignedToGroup( TaskGroup ) - - local TaskGroupName = TaskGroup:GetName() - - if self:IsStateAssigned() then - if TaskGroup:GetState( TaskGroup, "Assigned" ) == self then - return true - end - end - - return false -end - ---- Returns if the @{Task} has still alive and assigned Units. --- @param #TASK self --- @return #boolean -function TASK:HasAliveUnits() - self:F() - - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if self:IsStateAssigned() then - if self:IsAssignedToGroup( TaskGroup ) then - for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do - if TaskUnit:IsAlive() then - self:T( { HasAliveUnits = true } ) - return true - end - end - end - end - end - - self:T( { HasAliveUnits = false } ) - return false -end - ---- Set the menu options of the @{Task} to all the groups in the SetGroup. --- @param #TASK self -function TASK:SetMenu() - self:F() - - self.SetGroup:Flush() - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if self:IsStatePlanned() or self:IsStateReplanned() then - self:SetMenuForGroup( TaskGroup ) - end - end -end - - ---- Remove the menu options of the @{Task} to all the groups in the SetGroup. --- @param #TASK self --- @return #TASK self -function TASK:RemoveMenu() - - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - self:RemoveMenuForGroup( TaskGroup ) - end -end - - ---- Set the Menu for a Group --- @param #TASK self -function TASK:SetMenuForGroup( TaskGroup ) - - if not self:IsAssignedToGroup( TaskGroup ) then - self:SetPlannedMenuForGroup( TaskGroup, self:GetTaskName() ) - else - self:SetAssignedMenuForGroup( TaskGroup ) - end -end - - ---- Set the planned menu option of the @{Task}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @param #string MenuText The menu text. --- @return #TASK self -function TASK:SetPlannedMenuForGroup( TaskGroup, MenuText ) - self:E( TaskGroup:GetName() ) - - local Mission = self:GetMission() - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - - local TaskType = self:GetType() - local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, MissionMenu ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, MenuText, TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ) - - return self -end - ---- Set the assigned menu options of the @{Task}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK self -function TASK:SetAssignedMenuForGroup( TaskGroup ) - self:E( TaskGroup:GetName() ) - - local Mission = self:GetMission() - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - - self:E( { MissionMenu = MissionMenu } ) - - local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Task Status", MissionMenu, self.MenuTaskStatus, { self = self, TaskGroup = TaskGroup } ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Abort Task", MissionMenu, self.MenuTaskAbort, { self = self, TaskGroup = TaskGroup } ) - - return self -end - ---- Remove the menu option of the @{Task} for a @{Group}. --- @param #TASK self --- @param Wrapper.Group#GROUP TaskGroup --- @return #TASK self -function TASK:RemoveMenuForGroup( TaskGroup ) - - local Mission = self:GetMission() - local MissionName = Mission:GetName() - - local MissionMenu = Mission:GetMissionMenu( TaskGroup ) - MissionMenu:Remove() -end - -function TASK.MenuAssignToGroup( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - self:E( "Assigned menu selected") - - self:AssignToGroup( TaskGroup ) -end - -function TASK.MenuTaskStatus( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - --self:AssignToGroup( TaskGroup ) -end - -function TASK.MenuTaskAbort( MenuParam ) - - local self = MenuParam.self - local TaskGroup = MenuParam.TaskGroup - - --self:AssignToGroup( TaskGroup ) -end - - - ---- Returns the @{Task} name. --- @param #TASK self --- @return #string TaskName -function TASK:GetTaskName() - return self.TaskName -end - - - - ---- Get the default or currently assigned @{Process} template with key ProcessName. --- @param #TASK self --- @param #string ProcessName --- @return Core.Fsm#FSM_PROCESS -function TASK:GetProcessTemplate( ProcessName ) - - local ProcessTemplate = self.ProcessClasses[ProcessName] - - return ProcessTemplate -end - - - --- TODO: Obscolete? ---- Fail processes from @{Task} with key @{Unit} --- @param #TASK self --- @param #string TaskUnitName --- @return #TASK self -function TASK:FailProcesses( TaskUnitName ) - - for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do - local Process = ProcessData - Process.Fsm:Fail() - end -end - ---- Add a FiniteStateMachine to @{Task} with key Task@{Unit} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:SetStateMachine( TaskUnit, Fsm ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - self.Fsm[TaskUnit] = Fsm - - return Fsm -end - ---- Remove FiniteStateMachines from @{Task} with key Task@{Unit} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:RemoveStateMachine( TaskUnit ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - self.Fsm[TaskUnit] = nil - collectgarbage() - self:T( "Garbage Collected, Processes should be finalized now ...") -end - ---- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task} --- @param #TASK self --- @param Wrapper.Unit#UNIT TaskUnit --- @return #TASK self -function TASK:HasStateMachine( TaskUnit ) - self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } ) - - return ( self.Fsm[TaskUnit] ~= nil ) -end - - ---- Gets the Scoring of the task --- @param #TASK self --- @return Functional.Scoring#SCORING Scoring -function TASK:GetScoring() - return self.Mission:GetScoring() -end - - ---- Gets the Task Index, which is a combination of the Task type, the Task name. --- @param #TASK self --- @return #string The Task ID -function TASK:GetTaskIndex() - - local TaskType = self:GetType() - local TaskName = self:GetName() - - return TaskType .. "." .. TaskName -end - ---- Sets the Name of the Task --- @param #TASK self --- @param #string TaskName -function TASK:SetName( TaskName ) - self.TaskName = TaskName -end - ---- Gets the Name of the Task --- @param #TASK self --- @return #string The Task Name -function TASK:GetName() - return self.TaskName -end - ---- Sets the Type of the Task --- @param #TASK self --- @param #string TaskType -function TASK:SetType( TaskType ) - self.TaskType = TaskType -end - ---- Gets the Type of the Task --- @param #TASK self --- @return #string TaskType -function TASK:GetType() - return self.TaskType -end - ---- Sets the ID of the Task --- @param #TASK self --- @param #string TaskID -function TASK:SetID( TaskID ) - self.TaskID = TaskID -end - ---- Gets the ID of the Task --- @param #TASK self --- @return #string TaskID -function TASK:GetID() - return self.TaskID -end - - ---- Sets a @{Task} to status **Success**. --- @param #TASK self -function TASK:StateSuccess() - self:SetState( self, "State", "Success" ) - return self -end - ---- Is the @{Task} status **Success**. --- @param #TASK self -function TASK:IsStateSuccess() - return self:Is( "Success" ) -end - ---- Sets a @{Task} to status **Failed**. --- @param #TASK self -function TASK:StateFailed() - self:SetState( self, "State", "Failed" ) - return self -end - ---- Is the @{Task} status **Failed**. --- @param #TASK self -function TASK:IsStateFailed() - return self:Is( "Failed" ) -end - ---- Sets a @{Task} to status **Planned**. --- @param #TASK self -function TASK:StatePlanned() - self:SetState( self, "State", "Planned" ) - return self -end - ---- Is the @{Task} status **Planned**. --- @param #TASK self -function TASK:IsStatePlanned() - return self:Is( "Planned" ) -end - ---- Sets a @{Task} to status **Assigned**. --- @param #TASK self -function TASK:StateAssigned() - self:SetState( self, "State", "Assigned" ) - return self -end - ---- Is the @{Task} status **Assigned**. --- @param #TASK self -function TASK:IsStateAssigned() - return self:Is( "Assigned" ) -end - ---- Sets a @{Task} to status **Hold**. --- @param #TASK self -function TASK:StateHold() - self:SetState( self, "State", "Hold" ) - return self -end - ---- Is the @{Task} status **Hold**. --- @param #TASK self -function TASK:IsStateHold() - return self:Is( "Hold" ) -end - ---- Sets a @{Task} to status **Replanned**. --- @param #TASK self -function TASK:StateReplanned() - self:SetState( self, "State", "Replanned" ) - return self -end - ---- Is the @{Task} status **Replanned**. --- @param #TASK self -function TASK:IsStateReplanned() - return self:Is( "Replanned" ) -end - ---- Gets the @{Task} status. --- @param #TASK self -function TASK:GetStateString() - return self:GetState( self, "State" ) -end - ---- Sets a @{Task} briefing. --- @param #TASK self --- @param #string TaskBriefing --- @return #TASK self -function TASK:SetBriefing( TaskBriefing ) - self.TaskBriefing = TaskBriefing - return self -end - - - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterAssigned( From, Event, To ) - - self:E("Task Assigned") - - self:MessageToGroups( "Task " .. self:GetName() .. " has been assigned to your group." ) - self:GetMission():__Start() -end - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterSuccess( From, Event, To ) - - self:E( "Task Success" ) - - self:MessageToGroups( "Task " .. self:GetName() .. " is successful! Good job!" ) - self:UnAssignFromGroups() - - self:GetMission():__Complete() - -end - - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterAborted( From, Event, To ) - - self:E( "Task Aborted" ) - - self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been aborted! Task may be replanned." ) - - self:UnAssignFromGroups() -end - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onenterFailed( From, Event, To ) - - self:E( "Task Failed" ) - - self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has failed!" ) - - self:UnAssignFromGroups() -end - ---- FSM function for a TASK --- @param #TASK self --- @param #string Event --- @param #string From --- @param #string To -function TASK:onstatechange( From, Event, To ) - - if self:IsTrace() then - MESSAGE:New( "@ Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll() - end - - if self.Scores[To] then - local Scoring = self:GetScoring() - if Scoring then - self:E( { self.Scores[To].ScoreText, self.Scores[To].Score } ) - Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score ) - end - end - -end - -do -- Reporting - ---- Create a summary report of the Task. --- List the Task Name and Status --- @param #TASK self --- @return #string -function TASK:ReportSummary() - - local Report = REPORT:New() - - -- List the name of the Task. - local Name = self:GetName() - - -- Determine the status of the Task. - local State = self:GetState() - - Report:Add( "Task " .. Name .. " - State '" .. State ) - - return Report:Text() -end - - ---- Create a detailed report of the Task. --- List the Task Status, and the Players assigned to the Task. --- @param #TASK self --- @return #string -function TASK:ReportDetails() - - local Report = REPORT:New() - - -- List the name of the Task. - local Name = self:GetName() - - -- Determine the status of the Task. - local State = self:GetState() - - - -- Loop each Unit active in the Task, and find Player Names. - local PlayerNames = {} - for PlayerGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do - local Player = PlayerGroup -- Wrapper.Group#GROUP - for PlayerUnitID, PlayerUnit in pairs( PlayerGroup:GetUnits() ) do - local PlayerUnit = PlayerUnit -- Wrapper.Unit#UNIT - if PlayerUnit and PlayerUnit:IsAlive() then - local PlayerName = PlayerUnit:GetPlayerName() - PlayerNames[#PlayerNames+1] = PlayerName - end - end - local PlayerNameText = table.concat( PlayerNames, ", " ) - Report:Add( "Task " .. Name .. " - State '" .. State .. "' - Players " .. PlayerNameText ) - end - - -- Loop each Process in the Task, and find Reporting Details. - - return Report:Text() -end - - -end -- Reporting --- This module contains the DETECTION_MANAGER class and derived classes. --- --- === --- --- 1) @{Tasking.DetectionManager#DETECTION_MANAGER} class, extends @{Core.Base#BASE} --- ==================================================================== --- The @{Tasking.DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. --- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. --- --- 1.1) DETECTION_MANAGER constructor: --- ----------------------------------- --- * @{Tasking.DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. --- --- 1.2) DETECTION_MANAGER reporting: --- --------------------------------- --- Derived DETECTION_MANAGER classes will reports detected units using the method @{Tasking.DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. --- --- The time interval in seconds of the reporting can be changed using the methods @{Tasking.DetectionManager#DETECTION_MANAGER.SetReportInterval}(). --- To control how long a reporting message is displayed, use @{Tasking.DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}(). --- Derived classes need to implement the method @{Tasking.DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. --- --- Reporting can be started and stopped using the methods @{Tasking.DetectionManager#DETECTION_MANAGER.StartReporting}() and @{Tasking.DetectionManager#DETECTION_MANAGER.StopReporting}() respectively. --- If an ad-hoc report is requested, use the method @{Tasking.DetectionManager#DETECTION_MANAGER#ReportNow}(). --- --- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. --- --- === --- --- 2) @{Tasking.DetectionManager#DETECTION_REPORTING} class, extends @{Tasking.DetectionManager#DETECTION_MANAGER} --- ========================================================================================= --- The @{Tasking.DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Tasking.DetectionManager#DETECTION_MANAGER} class. --- --- 2.1) DETECTION_REPORTING constructor: --- ------------------------------- --- The @{Tasking.DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance. --- --- === --- --- 3) @{#DETECTION_DISPATCHER} class, extends @{#DETECTION_MANAGER} --- ================================================================ --- The @{#DETECTION_DISPATCHER} class implements the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of FAC (groups). --- The FAC will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched. --- Find a summary below describing for which situation a task type is created: --- --- * **CAS Task**: Is created when there are enemy ground units within range of the FAC, while there are friendly units in the FAC perimeter. --- * **BAI Task**: Is created when there are enemy ground units within range of the FAC, while there are NO other friendly units within the FAC perimeter. --- * **SEAD Task**: Is created when there are enemy ground units wihtin range of the FAC, with air search radars. --- --- Other task types will follow... --- --- 3.1) DETECTION_DISPATCHER constructor: --- -------------------------------------- --- The @{#DETECTION_DISPATCHER.New}() method creates a new DETECTION_DISPATCHER instance. --- --- === --- --- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing --- ### Author: FlightControl - Framework Design & Programming --- --- @module DetectionManager - -do -- DETECTION MANAGER - - --- DETECTION_MANAGER class. - -- @type DETECTION_MANAGER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @extends Base#BASE - DETECTION_MANAGER = { - ClassName = "DETECTION_MANAGER", - SetGroup = nil, - Detection = nil, - } - - --- FAC constructor. - -- @param #DETECTION_MANAGER self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:New( SetGroup, Detection ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) -- Functional.Detection#DETECTION_MANAGER - - self.SetGroup = SetGroup - self.Detection = Detection - - self:SetReportInterval( 30 ) - self:SetReportDisplayTime( 25 ) - - return self - end - - --- Set the reporting time interval. - -- @param #DETECTION_MANAGER self - -- @param #number ReportInterval The interval in seconds when a report needs to be done. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:SetReportInterval( ReportInterval ) - self:F2() - - self._ReportInterval = ReportInterval - end - - - --- Set the reporting message display time. - -- @param #DETECTION_MANAGER self - -- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:SetReportDisplayTime( ReportDisplayTime ) - self:F2() - - self._ReportDisplayTime = ReportDisplayTime - end - - --- Get the reporting message display time. - -- @param #DETECTION_MANAGER self - -- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. - function DETECTION_MANAGER:GetReportDisplayTime() - self:F2() - - return self._ReportDisplayTime - end - - - - --- Reports the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_MANAGER self - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:ReportDetected( Detection ) - self:F2() - - end - - --- Schedule the FAC reporting. - -- @param #DETECTION_MANAGER self - -- @param #number DelayTime The delay in seconds to wait the reporting. - -- @param #number ReportInterval The repeat interval in seconds for the reporting to happen repeatedly. - -- @return #DETECTION_MANAGER self - function DETECTION_MANAGER:Schedule( DelayTime, ReportInterval ) - self:F2() - - self._ScheduleDelayTime = DelayTime - - self:SetReportInterval( ReportInterval ) - - self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "DetectionManager" }, self._ScheduleDelayTime, self._ReportInterval ) - return self - end - - --- Report the detected @{Wrapper.Unit#UNIT}s detected within the @{Functional.Detection#DETECTION_BASE} object to the @{Set#SET_GROUP}s. - -- @param #DETECTION_MANAGER self - function DETECTION_MANAGER:_FacScheduler( SchedulerName ) - self:F2( { SchedulerName } ) - - return self:ProcessDetected( self.Detection ) - --- self.SetGroup:ForEachGroup( --- --- @param Wrapper.Group#GROUP Group --- function( Group ) --- if Group:IsAlive() then --- return self:ProcessDetected( self.Detection ) --- end --- end --- ) - --- return true - end - -end - - -do -- DETECTION_REPORTING - - --- DETECTION_REPORTING class. - -- @type DETECTION_REPORTING - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @extends #DETECTION_MANAGER - DETECTION_REPORTING = { - ClassName = "DETECTION_REPORTING", - } - - - --- DETECTION_REPORTING constructor. - -- @param #DETECTION_REPORTING self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_AREAS Detection - -- @return #DETECTION_REPORTING self - function DETECTION_REPORTING:New( SetGroup, Detection ) - - -- Inherits from DETECTION_MANAGER - local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_REPORTING - - self:Schedule( 1, 30 ) - return self - end - - --- Creates a string of the detected items in a @{Detection}. - -- @param #DETECTION_MANAGER self - -- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Functional.Detection#DETECTION_BASE} object. - -- @return #DETECTION_MANAGER self - function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet ) - self:F2() - - local MT = {} -- Message Text - local UnitTypes = {} - - for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do - local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT - if DetectedUnit:IsAlive() then - local UnitType = DetectedUnit:GetTypeName() - - if not UnitTypes[UnitType] then - UnitTypes[UnitType] = 1 - else - UnitTypes[UnitType] = UnitTypes[UnitType] + 1 - end - end - end - - for UnitTypeID, UnitType in pairs( UnitTypes ) do - MT[#MT+1] = UnitType .. " of " .. UnitTypeID - end - - return table.concat( MT, ", " ) - end - - - - --- Reports the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_REPORTING self - -- @param Wrapper.Group#GROUP Group The @{Group} object to where the report needs to go. - -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_BASE} object. - -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. - function DETECTION_REPORTING:ProcessDetected( Group, Detection ) - self:F2( Group ) - - self:E( Group ) - local DetectedMsg = {} - for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do - local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea - DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set ) - end - local FACGroup = Detection:GetDetectionGroups() - FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group ) - - return true - end - -end - -do -- DETECTION_DISPATCHER - - --- DETECTION_DISPATCHER class. - -- @type DETECTION_DISPATCHER - -- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to. - -- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. - -- @field Tasking.Mission#MISSION Mission - -- @field Wrapper.Group#GROUP CommandCenter - -- @extends Tasking.DetectionManager#DETECTION_MANAGER - DETECTION_DISPATCHER = { - ClassName = "DETECTION_DISPATCHER", - Mission = nil, - CommandCenter = nil, - Detection = nil, - } - - - --- DETECTION_DISPATCHER constructor. - -- @param #DETECTION_DISPATCHER self - -- @param Set#SET_GROUP SetGroup - -- @param Functional.Detection#DETECTION_BASE Detection - -- @return #DETECTION_DISPATCHER self - function DETECTION_DISPATCHER:New( Mission, CommandCenter, SetGroup, Detection ) - - -- Inherits from DETECTION_MANAGER - local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_DISPATCHER - - self.Detection = Detection - self.CommandCenter = CommandCenter - self.Mission = Mission - - self:Schedule( 30 ) - return self - end - - - --- Creates a SEAD task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Set#SET_UNIT TargetSetUnit: The target set of units. - -- @return #nil If there are no targets to be set. - function DETECTION_DISPATCHER:EvaluateSEAD( DetectedArea ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local RadarCount = DetectedSet:HasSEAD() - - if RadarCount > 0 then - - -- Here we're doing something advanced... We're copying the DetectedSet, but making a new Set only with SEADable Radar units in it. - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterHasSEAD() - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Creates a CAS task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateCAS( DetectedArea ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local GroundUnitCount = DetectedSet:HasGroundUnits() - local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea ) - - if GroundUnitCount > 0 and FriendliesNearBy == true then - - -- Copy the Set - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Creates a BAI task when there are targets for it. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateBAI( DetectedArea, FriendlyCoalition ) - self:F( { DetectedArea.AreaID } ) - - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - - - -- Determine if the set has radar targets. If it does, construct a SEAD task. - local GroundUnitCount = DetectedSet:HasGroundUnits() - local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea ) - - if GroundUnitCount > 0 and FriendliesNearBy == false then - - -- Copy the Set - local TargetSetUnit = SET_UNIT:New() - TargetSetUnit:SetDatabase( DetectedSet ) - TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection. - - return TargetSetUnit - end - - return nil - end - - --- Evaluates the removal of the Task from the Mission. - -- Can only occur when the DetectedArea is Changed AND the state of the Task is "Planned". - -- @param #DETECTION_DISPATCHER self - -- @param Tasking.Mission#MISSION Mission - -- @param Tasking.Task#TASK Task - -- @param Functional.Detection#DETECTION_AREAS.DetectedArea DetectedArea - -- @return Tasking.Task#TASK - function DETECTION_DISPATCHER:EvaluateRemoveTask( Mission, Task, DetectedArea ) - - if Task then - if Task:IsStatePlanned() and DetectedArea.Changed == true then - self:E( "Removing Tasking: " .. Task:GetTaskName() ) - Task = Mission:RemoveTask( Task ) - end - end - - return Task - end - - - --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. - -- @param #DETECTION_DISPATCHER self - -- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_AREAS} object. - -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. - function DETECTION_DISPATCHER:ProcessDetected( Detection ) - self:F2() - - local AreaMsg = {} - local TaskMsg = {} - local ChangeMsg = {} - - local Mission = self.Mission - - --- First we need to the detected targets. - for DetectedAreaID, DetectedAreaData in ipairs( Detection:GetDetectedAreas() ) do - - local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea - local DetectedSet = DetectedArea.Set - local DetectedZone = DetectedArea.Zone - self:E( { "Targets in DetectedArea", DetectedArea.AreaID, DetectedSet:Count(), tostring( DetectedArea ) } ) - DetectedSet:Flush() - - local AreaID = DetectedArea.AreaID - - -- Evaluate SEAD Tasking - local SEADTask = Mission:GetTask( "SEAD." .. AreaID ) - SEADTask = self:EvaluateRemoveTask( Mission, SEADTask, DetectedArea ) - if not SEADTask then - local TargetSetUnit = self:EvaluateSEAD( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - SEADTask = Mission:AddTask( TASK_SEAD:New( Mission, self.SetGroup, "SEAD." .. AreaID, TargetSetUnit , DetectedZone ) ) - end - end - if SEADTask and SEADTask:IsStatePlanned() then - self:E( "Planned" ) - --SEADTask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. SEADTask:GetStateString() .. " SEAD " .. AreaID .. " - " .. SEADTask.TargetSetUnit:GetUnitTypesText() - end - - -- Evaluate CAS Tasking - local CASTask = Mission:GetTask( "CAS." .. AreaID ) - CASTask = self:EvaluateRemoveTask( Mission, CASTask, DetectedArea ) - if not CASTask then - local TargetSetUnit = self:EvaluateCAS( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - CASTask = Mission:AddTask( TASK_A2G:New( Mission, self.SetGroup, "CAS." .. AreaID, "CAS", TargetSetUnit , DetectedZone, DetectedArea.NearestFAC ) ) - end - end - if CASTask and CASTask:IsStatePlanned() then - --CASTask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. CASTask:GetStateString() .. " CAS " .. AreaID .. " - " .. CASTask.TargetSetUnit:GetUnitTypesText() - end - - -- Evaluate BAI Tasking - local BAITask = Mission:GetTask( "BAI." .. AreaID ) - BAITask = self:EvaluateRemoveTask( Mission, BAITask, DetectedArea ) - if not BAITask then - local TargetSetUnit = self:EvaluateBAI( DetectedArea, self.CommandCenter:GetCoalition() ) -- Returns a SetUnit if there are targets to be SEADed... - if TargetSetUnit then - BAITask = Mission:AddTask( TASK_A2G:New( Mission, self.SetGroup, "BAI." .. AreaID, "BAI", TargetSetUnit , DetectedZone, DetectedArea.NearestFAC ) ) - end - end - if BAITask and BAITask:IsStatePlanned() then - --BAITask:SetPlannedMenu() - TaskMsg[#TaskMsg+1] = " - " .. BAITask:GetStateString() .. " BAI " .. AreaID .. " - " .. BAITask.TargetSetUnit:GetUnitTypesText() - end - - if #TaskMsg > 0 then - - local ThreatLevel = Detection:GetTreatLevelA2G( DetectedArea ) - - local DetectedAreaVec3 = DetectedZone:GetVec3() - local DetectedAreaPointVec3 = POINT_VEC3:New( DetectedAreaVec3.x, DetectedAreaVec3.y, DetectedAreaVec3.z ) - local DetectedAreaPointLL = DetectedAreaPointVec3:ToStringLL( 3, true ) - AreaMsg[#AreaMsg+1] = string.format( " - Area #%d - %s - Threat Level [%s] (%2d)", - DetectedAreaID, - DetectedAreaPointLL, - string.rep( "â– ", ThreatLevel ), - ThreatLevel - ) - - -- Loop through the changes ... - local ChangeText = Detection:GetChangeText( DetectedArea ) - - if ChangeText ~= "" then - ChangeMsg[#ChangeMsg+1] = string.gsub( string.gsub( ChangeText, "\n", "%1 - " ), "^.", " - %1" ) - end - end - - -- OK, so the tasking has been done, now delete the changes reported for the area. - Detection:AcceptChanges( DetectedArea ) - - end - - -- TODO set menus using the HQ coordinator - Mission:GetCommandCenter():SetMenu() - - if #AreaMsg > 0 then - for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if not TaskGroup:GetState( TaskGroup, "Assigned" ) then - self.CommandCenter:MessageToGroup( - string.format( "HQ Reporting - Target areas for mission '%s':\nAreas:\n%s\n\nTasks:\n%s\n\nChanges:\n%s ", - self.Mission:GetName(), - table.concat( AreaMsg, "\n" ), - table.concat( TaskMsg, "\n" ), - table.concat( ChangeMsg, "\n" ) - ), self:GetReportDisplayTime(), TaskGroup - ) - end - end - end - - return true - end - -end--- This module contains the TASK_SEAD classes. --- --- 1) @{#TASK_SEAD} class, extends @{Tasking.Task#TASK} --- ================================================= --- The @{#TASK_SEAD} class defines a SEAD task for a @{Set} of Target Units, located at a Target Zone, --- based on the tasking capabilities defined in @{Tasking.Task#TASK}. --- The TASK_SEAD is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: --- --- * **None**: Start of the process --- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. --- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. --- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task_SEAD - - - -do -- TASK_SEAD - - --- The TASK_SEAD class - -- @type TASK_SEAD - -- @field Set#SET_UNIT TargetSetUnit - -- @extends Tasking.Task#TASK - TASK_SEAD = { - ClassName = "TASK_SEAD", - } - - --- Instantiates a new TASK_SEAD. - -- @param #TASK_SEAD self - -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #TASK_SEAD self - function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TargetZone ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, "SEAD" ) ) -- Tasking.Task_SEAD#TASK_SEAD - self:F() - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - - local Fsm = self:GetUnitProcess() - - Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "Route", Rejected = "Eject" } ) - Fsm:AddProcess ( "Assigned", "Route", ACT_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } ) - Fsm:AddTransition( "Rejected", "Eject", "Planned" ) - Fsm:AddTransition( "Arrived", "Update", "Updated" ) - Fsm:AddProcess ( "Updated", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, "SEAD" ), { Accounted = "Success" } ) - Fsm:AddProcess ( "Updated", "Smoke", ACT_ASSIST_SMOKE_TARGETS_ZONE:New( self.TargetSetUnit, self.TargetZone ) ) - Fsm:AddTransition( "Accounted", "Success", "Success" ) - Fsm:AddTransition( "Failed", "Fail", "Failed" ) - - function Fsm:onenterUpdated( TaskUnit ) - self:E( { self } ) - self:Account() - self:Smoke() - end - --- _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self ) --- _EVENTDISPATCHER:OnDead( self._EventDead, self ) --- _EVENTDISPATCHER:OnCrash( self._EventDead, self ) --- _EVENTDISPATCHER:OnPilotDead( self._EventDead, self ) - - return self - end - - --- @param #TASK_SEAD self - function TASK_SEAD:GetPlannedMenuText() - return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" - end - -end ---- (AI) (SP) (MP) Tasking for Air to Ground Processes. --- --- 1) @{#TASK_A2G} class, extends @{Tasking.Task#TASK} --- ================================================= --- The @{#TASK_A2G} class defines a CAS or BAI task of a @{Set} of Target Units, --- located at a Target Zone, based on the tasking capabilities defined in @{Tasking.Task#TASK}. --- The TASK_A2G is implemented using a @{Statemachine#FSM_TASK}, and has the following statuses: --- --- * **None**: Start of the process --- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Fsm.Assign#ACT_ASSIGN_ACCEPT} is started to accept the task. --- * **Assigned**: The SEAD task is assigned to a @{Wrapper.Group#GROUP}. Upon Assigned, the sub-process @{Process_Fsm.Route#ACT_ROUTE} is started to route the active Units in the Group to the attack zone. --- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. --- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. --- --- === --- --- ### Authors: FlightControl - Design and Programming --- --- @module Task_A2G - - -do -- TASK_A2G - - --- The TASK_A2G class - -- @type TASK_A2G - -- @extends Tasking.Task#TASK - TASK_A2G = { - ClassName = "TASK_A2G", - } - - --- Instantiates a new TASK_A2G. - -- @param #TASK_A2G self - -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. - -- @param #string TaskName The name of the Task. - -- @param #string TaskType BAI or CAS - -- @param Set#SET_UNIT UnitSetTargets - -- @param Core.Zone#ZONE_BASE TargetZone - -- @return #TASK_A2G self - function TASK_A2G:New( Mission, SetGroup, TaskName, TaskType, TargetSetUnit, TargetZone, FACUnit ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) - self:F() - - self.TargetSetUnit = TargetSetUnit - self.TargetZone = TargetZone - self.FACUnit = FACUnit - - local A2GUnitProcess = self:GetUnitProcess() - - A2GUnitProcess:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( "Attack the Area" ), { Assigned = "Route", Rejected = "Eject" } ) - A2GUnitProcess:AddProcess ( "Assigned", "Route", ACT_ROUTE_ZONE:New( self.TargetZone ), { Arrived = "Update" } ) - A2GUnitProcess:AddTransition( "Rejected", "Eject", "Planned" ) - A2GUnitProcess:AddTransition( "Arrived", "Update", "Updated" ) - A2GUnitProcess:AddProcess ( "Updated", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, "Attack" ), { Accounted = "Success" } ) - A2GUnitProcess:AddProcess ( "Updated", "Smoke", ACT_ASSIST_SMOKE_TARGETS_ZONE:New( self.TargetSetUnit, self.TargetZone ) ) - --Fsm:AddProcess ( "Updated", "JTAC", PROCESS_JTAC:New( self, TaskUnit, self.TargetSetUnit, self.FACUnit ) ) - A2GUnitProcess:AddTransition( "Accounted", "Success", "Success" ) - A2GUnitProcess:AddTransition( "Failed", "Fail", "Failed" ) - - function A2GUnitProcess:onenterUpdated( TaskUnit ) - self:E( { self } ) - self:Account() - self:Smoke() - end - - - - --_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self ) - --_EVENTDISPATCHER:OnDead( self._EventDead, self ) - --_EVENTDISPATCHER:OnCrash( self._EventDead, self ) - --_EVENTDISPATCHER:OnPilotDead( self._EventDead, self ) - - return self - end - - --- @param #TASK_A2G self - function TASK_A2G:GetPlannedMenuText() - return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" - end - - end - - - ---- The main include file for the MOOSE system. - ---- Core Routines -Include.File( "Utilities/Routines" ) -Include.File( "Utilities/Utils" ) - ---- Core Classes -Include.File( "Core/Base" ) -Include.File( "Core/Scheduler" ) -Include.File( "Core/ScheduleDispatcher") -Include.File( "Core/Event" ) -Include.File( "Core/Menu" ) -Include.File( "Core/Zone" ) -Include.File( "Core/Database" ) -Include.File( "Core/Set" ) -Include.File( "Core/Point" ) -Include.File( "Core/Message" ) -Include.File( "Core/Fsm" ) - ---- Wrapper Classes -Include.File( "Wrapper/Object" ) -Include.File( "Wrapper/Identifiable" ) -Include.File( "Wrapper/Positionable" ) -Include.File( "Wrapper/Controllable" ) -Include.File( "Wrapper/Group" ) -Include.File( "Wrapper/Unit" ) -Include.File( "Wrapper/Client" ) -Include.File( "Wrapper/Static" ) -Include.File( "Wrapper/Airbase" ) - ---- Functional Classes -Include.File( "Functional/Scoring" ) -Include.File( "Functional/CleanUp" ) -Include.File( "Functional/Spawn" ) -Include.File( "Functional/Movement" ) -Include.File( "Functional/Sead" ) -Include.File( "Functional/Escort" ) -Include.File( "Functional/MissileTrainer" ) -Include.File( "Functional/AirbasePolice" ) -Include.File( "Functional/Detection" ) - ---- AI Classes -Include.File( "AI/AI_Balancer" ) -Include.File( "AI/AI_Patrol" ) -Include.File( "AI/AI_Cargo" ) -Include.File( "AI/AI_Cas" ) - ---- Actions -Include.File( "Actions/Act_Assign" ) -Include.File( "Actions/Act_Route" ) -Include.File( "Actions/Act_Account" ) -Include.File( "Actions/Act_Assist" ) - ---- Task Handling Classes -Include.File( "Tasking/CommandCenter" ) -Include.File( "Tasking/Mission" ) -Include.File( "Tasking/Task" ) -Include.File( "Tasking/DetectionManager" ) -Include.File( "Tasking/Task_SEAD" ) -Include.File( "Tasking/Task_A2G" ) - - --- The order of the declarations is important here. Don't touch it. - ---- Declare the event dispatcher based on the EVENT class -_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT - ---- Declare the timer dispatcher based on the SCHEDULEDISPATCHER class -_SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER - ---- Declare the main database object, which is used internally by the MOOSE classes. -_DATABASE = DATABASE:New() -- Database#DATABASE +Include.ProgramPath = "Scripts/Moose/" +env.info( "Include.ProgramPath = " .. Include.ProgramPath) +Include.Files = {} +Include.File( "Moose" ) -BASE:TraceOnOff( false ) +BASE:TraceOnOff( true ) env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.miz b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.miz index 0696929e0b8a320d1141db4090f0b3300f1ae097..4fd7379dc3bea036a9ffbfa0fc29fe8645f4915d 100644 GIT binary patch delta 533 zcmcb=iFft~#tj#A`9Chy_2S&pV^_k+z>v<&F!{c&bp6y|NB=_xB6gco{y$tQZpO!K za;&9=`H+grp^n+?$s8-AwY_&uE14_)xPH6t3fJWqy|-WgzW04~{BN%x#UVvnOfSAw z*+!^&N*#VvXBw%uY(s=^{<}28B{!d#F;9N)#If(Wh;Hi&&NH0qLaT!cPMqqx!WI5o za1L+V^yY^jYF5|R>+wz9cig2<(k3a^wC(Mk9Nmg@vko26U+*UqJN-<~rMBm7Rt?FA z-nH+$uBlnD@W9dQ{OT)sSI9n;x@E~~Iiq)4fm8F}FYSFZ1)DUA64hKBmaaJ9>zb`O zPi5V;h_^Z2bDQH=xfa9tU8` zQ=V9{?3rb$|BN@lo0&y~fq{Wz`)&c|{ch+nGrcpM*;MSJN_ytS+)IoPg1`K=&V$j@ zuY@z}Fz4wrOlOW@He%KYW0-CMV!VoBn4TNK?8FomH+`2qv&{6f5zJc5mkJoB|B7IC UWR5Llm~I!zEX~GS0<@O_09>u-bN~PV delta 190741 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 S1EEp_llpfX22oW50001};sbI3 diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz b/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz index 98af7ed6c70103711c2f2252a289b8eda9765994..ea244231e7e19263086384c4c1a8f8c9d4acb795 100644 GIT binary patch delta 29566 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 literal 219146 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

-jtSpj@T^Z!X7?hP$y~O~_hk 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 Hzaakw3+_2P diff --git a/Moose Test Missions/CAS - Close Air Support/CAS-001 - CAS in a ZONE/CAS-001 - Manual Test.miz b/Moose Test Missions/CAS - Close Air Support/CAS-001 - CAS in a ZONE/CAS-001 - Manual Test.miz index 37b9b2e5631142ed968165dd91f72cc0b0cd7dd3..1b0494ad78ae9e7621440ec9a597ea7fb1120113 100644 GIT binary patch delta 514 zcmca~k*BYpal-|1{*McFy*Rh@*p)CcFr+gxOujEJT|YJ0(f^Qvh~4It{|}dnoAEK5 z9BXM|KBS^@sAD#JGRMkjZSP&vO6H0`uHUY^!gcvY@9o#W?|ok#|J&2o1)}e-G5hzwkio4{q~5ZgKN7Rr<_ieW-H+_d2yqn^P+1JP!$bF$Zkg`1$&` zGP`>|duCbcKjRJXW@Zs#U|`_bzWW!`ZXNWPnck|-Y$|$DB|YI;SAB%=8uwW-Vq#Cx+=8HJGK@j=KOYVE_On Cm&s9`hPGj}9U~)@z#G7wed3Mt@kHpte5@kUV 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

LP+V=$f^r5RoV%y8gcbHv_=hD%lW99 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

ahM_cjkN49u=guB_49DR10;@Zic+i$ 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

Re(jcV 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

~p^m9t9>fG=NI8=k4+6d2+}H9hOQ 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%0D5Od6jp|qkLm^w)u)dm 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%0D<0cin2-*}4d_clgFx(tXtC`P*bEwat^ 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 diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.miz b/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.miz index 66df9bf376b7fda7429efc97118d32ad0b77450b..cfb5991b00dcf63707320f6cdcaf012576343454 100644 GIT binary patch delta 586 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 Or87&jxitapWB>q@IpQ|} delta 190767 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 Tyr-FA`s!?EX||j;puG$L0-)pf delta 190763 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 5 then BASE:E("Still alive") else BASE:E("Destroyed") - AICasZone:__Completed(1) + AICasZone:__Accomplish( 1 ) -- Now they should fly back to teh patrolzone and patrol. + Check:Stop(CheckScheduleID) end end, {}, 20, 60, 0.2 ) + + +-- When the targets in the zone are destroyed, (see scheduled function), the planes will return homs... +function AICasZone:OnAfterAccomplish( Controllable, From, Event, To ) + + AICasZone:__RTB( 1 ) +end diff --git a/Moose Test Missions/CAS - Close Air Support/CAS-001 - CAS in a ZONE/CAS-001 - CAS in a ZONE.miz b/Moose Test Missions/CAS - Close Air Support/CAS-001 - CAS in a ZONE/CAS-001 - CAS in a ZONE.miz index 75784d5da6b1a1ca4ddd149fe986f37bbdfdd270..47b4ad02d914d8352d68fe577ae839bb23329275 100644 GIT binary patch delta 14994 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