diff --git a/Moose Development/Moose/Airbase.lua b/Moose Development/Moose/Airbase.lua index 87ccf2ba9..15c4fc7d5 100644 --- a/Moose Development/Moose/Airbase.lua +++ b/Moose Development/Moose/Airbase.lua @@ -2,8 +2,8 @@ -- -- === -- --- 1) @{Airbase#AIRBASE} class, extends @{Base#BASE} --- ================================================= +-- 1) @{Airbase#AIRBASE} class, extends @{Positionable#POSITIONABLE} +-- ================================================================= -- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: -- -- * Support all DCS Airbase APIs. @@ -49,7 +49,7 @@ --- The AIRBASE class -- @type AIRBASE --- @extends Base#BASE +-- @extends Positionable#POSITIONABLE AIRBASE = { ClassName="AIRBASE", CategoryName = { @@ -63,13 +63,11 @@ AIRBASE = { --- Create a new AIRBASE from DCSAirbase. -- @param #AIRBASE self --- @param DCSAirbase#Airbase DCSAirbase --- @param Database#DATABASE Database +-- @param #string AirbaseName The name of the airbase. -- @return Airbase#AIRBASE function AIRBASE:Register( AirbaseName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( AirbaseName ) + local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) self.AirbaseName = AirbaseName return self end diff --git a/Moose Development/Moose/Base.lua b/Moose Development/Moose/Base.lua index 1737ebdfd..0c7361e41 100644 --- a/Moose Development/Moose/Base.lua +++ b/Moose Development/Moose/Base.lua @@ -440,7 +440,7 @@ end -- @param Arguments A #table or any field. function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -469,7 +469,7 @@ end -- @param Arguments A #table or any field. function BASE:F( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -485,7 +485,7 @@ end -- @param Arguments A #table or any field. function BASE:F2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -500,7 +500,7 @@ end -- @param Arguments A #table or any field. function BASE:F3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -515,7 +515,7 @@ end -- @param Arguments A #table or any field. function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -544,7 +544,7 @@ end -- @param Arguments A #table or any field. function BASE:T( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -560,7 +560,7 @@ end -- @param Arguments A #table or any field. function BASE:T2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -575,7 +575,7 @@ end -- @param Arguments A #table or any field. function BASE:T3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -590,21 +590,24 @@ end -- @param Arguments A #table or any field. function BASE:E( Arguments ) - 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 ) ) ) + 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 diff --git a/Moose Development/Moose/Cargo.lua b/Moose Development/Moose/Cargo.lua index 5a8913910..f4372934e 100644 --- a/Moose Development/Moose/Cargo.lua +++ b/Moose Development/Moose/Cargo.lua @@ -887,7 +887,6 @@ function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) end self:T( "Routing " .. CargoHostName ) - --routines.scheduleFunction( routines.goRoute, { CargoHostName, Points}, timer.getTime() + 4 ) SCHEDULER:New( self, routines.goRoute, { CargoHostName, Points }, 4 ) return Valid diff --git a/Moose Development/Moose/CleanUp.lua b/Moose Development/Moose/CleanUp.lua index 71554252b..b8525ebce 100644 --- a/Moose Development/Moose/CleanUp.lua +++ b/Moose Development/Moose/CleanUp.lua @@ -43,7 +43,6 @@ function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, _EVENTDISPATCHER:OnBirth( self._OnEventBirth, self ) - --self.CleanUpScheduler = routines.scheduleFunction( self._CleanUpScheduler, { self }, timer.getTime() + 1, TimeInterval ) self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) return self @@ -168,7 +167,6 @@ function CLEANUP:_EventShot( Event ) if ( CurrentLandingZoneID ) then -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. --_SEADmissile:destroy() - --routines.scheduleFunction( CLEANUP._DestroyMissile, { self, Event.Weapon }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) end end @@ -185,7 +183,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.IniDCSUnit }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) end end @@ -196,7 +193,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.TgtDCSUnit }, timer.getTime() + 0.1 ) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) end end diff --git a/Moose Development/Moose/Controllable.lua b/Moose Development/Moose/Controllable.lua new file mode 100644 index 000000000..c1c899bd5 --- /dev/null +++ b/Moose Development/Moose/Controllable.lua @@ -0,0 +1,2187 @@ +--- This module contains the CONTROLLABLE class. +-- +-- 1) @{Controllable#CONTROLLABLE} class, extends @{Positionable#POSITIONABLE} +-- =========================================================== +-- The @{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 @{Controllable#CONTROLLABLE.PushTask} or @{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 @{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 +-- @author FlightControl + +--- The CONTROLLABLE class +-- @type CONTROLLABLE +-- @extends Positionable#POSITIONABLE +-- @field DCSControllable#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 DCSControllable#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 + return self +end + +-- DCS Controllable methods support. + +--- Get the controller for the CONTROLLABLE. +-- @param #CONTROLLABLE self +-- @return 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 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 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 + SCHEDULER:New( 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 Controllable#CONTROLLABLE self +function CONTROLLABLE:SetTask( DCSTask, WaitTime ) + self:F2( { DCSTask } ) + + 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.setTask( Controller, DCSTask ) + + if not WaitTime then + WaitTime = 1 + end + SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) + + return self + end + + return nil +end + + +--- Return a condition section for a controlled task. +-- @param #CONTROLLABLE self +-- @param DCSTime#Time time +-- @param #string userFlag +-- @param #boolean userFlagValue +-- @param #string condition +-- @param DCSTime#Time duration +-- @param #number lastWayPoint +-- return DCSTask#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 DCSTask#Task DCSTask +-- @param #DCSStopCondition DCSStopCondition +-- @return DCSTask#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 DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} +-- @return DCSTask#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 DCSCommand#Command DCSCommand +-- @return DCSTask#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 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 DCSTask#Task +function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) + self:F2( { FromWayPoint, ToWayPoint, Index } ) + + 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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackControllable( AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- AttackControllable = { + -- id = 'AttackControllable', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 = { + unitId = AttackUnit:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + attackQtyLimit = AttackQtyLimit, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Delivering weapon at the point on the ground. +-- @param #CONTROLLABLE self +-- @param DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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:GetPointVec2() + 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 DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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 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 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 DCSTask#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 DCSTask#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 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 @{Zone#ZONE_RADIUS). +-- @param #CONTROLLABLE self +-- @param 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:GetPointVec2() + 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 Controllable#CONTROLLABLE FollowControllable The controllable to be followed. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFollow( FollowControllable, PointVec3, LastWaypointIndex ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex } ) + +-- Follow = { +-- id = 'Follow', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEscort( FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) + +-- Escort = { +-- id = 'Escort', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number, +-- engagementDistMax = Distance, +-- targetTypes = array of AttributeName, +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 DCSTypes#Vec2 PointVec2 The point to fire at. +-- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFireAtPoint( PointVec2, Radius ) + self:F2( { self.ControllableName, PointVec2, Radius } ) + + -- FireAtPoint = { + -- id = 'FireAtPoint', + -- params = { + -- point = Vec2, + -- radius = Distance, + -- } + -- } + + local DCSTask + DCSTask = { id = 'FireAtPoint', + params = { + point = PointVec2, + radius = Radius, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (GROUND) Hold ground controllable from moving. +-- @param #CONTROLLABLE self +-- @return DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFAC_AttackControllable( AttackControllable, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Designation, Datalink } ) + +-- FAC_AttackControllable = { +-- id = 'FAC_AttackControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_AttackControllable', + params = { + controllableId = AttackControllable:GetID(), + weaponType = WeaponType, + designation = Designation, + datalink = Datalink, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +-- EN-ROUTE TASKS FOR AIRBORNE CONTROLLABLES + +--- (AIR) Engaging targets of defined types. +-- @param #CONTROLLABLE self +-- @param 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 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 DCSTask#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 DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. +-- @param DCSTypes#Distance Radius Radius of the zone. +-- @param 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) + self:F2( { self.ControllableName, PointVec2, Radius, TargetTypes, Priority } ) + +-- EngageTargetsInZone = { +-- id = 'EngageTargetsInZone', +-- params = { +-- point = Vec2, +-- zoneRadius = Distance, +-- targetTypes = array of AttributeName, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'EngageTargetsInZone', + params = { + point = PointVec2, + 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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageControllable( AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- EngageControllable = { + -- id = 'EngageControllable ', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 DCSTask#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 DCSTask#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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskFAC_EngageControllable( AttackControllable, Priority, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Priority, Designation, Datalink } ) + +-- FAC_EngageControllable = { +-- id = 'FAC_EngageControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean, +-- priority = number, +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_EngageControllable', + params = { + controllableId = AttackControllable: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 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 DCSTask#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 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 DCSTask#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 DCSTypes#Vec2 Point The point where to wait. +-- @param #number Radius The radius of the embarking zone around the Point. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) + self:F2( { self.ControllableName, Point, Radius } ) + + local DCSTask --DCSTask#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 DCSTask#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 DCSTask#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 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 ):GetPointVec2() + + 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 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 ControllablePoint = self:GetUnit( 1 ):GetPointVec3() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.z + PointFrom.alt = ControllablePoint.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 ) + SCHEDULER:New( 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 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:GetPointVec2() + + 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:GetPointVec2() + 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 @{Airbase#AIRBASE} +-- A speed can be given in km/h. +-- A given formation can be given. +-- @param #CONTROLLABLE self +-- @param Airbase#AIRBASE ReturnAirbase The @{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:GetPointVec2() + 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:GetPointVec2() + + 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 @{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 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 Controllable#CONTROLLABLE self +-- @return 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 @{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 ) + + if WayPoints then + self.WayPoints = WayPoints + else + self.WayPoints = self:GetTaskRoute() + end + + return self +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 = CONTROLLABLE: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 ) + + 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 + + diff --git a/Moose Development/Moose/Database.lua b/Moose Development/Moose/Database.lua index 4659a0d3f..c75bafc30 100644 --- a/Moose Development/Moose/Database.lua +++ b/Moose Development/Moose/Database.lua @@ -119,6 +119,8 @@ end function DATABASE:AddUnit( DCSUnitName ) if not self.UNITS[DCSUnitName] then + local UnitRegister = UNIT:Register( DCSUnitName ) + self:E( UnitRegister.UnitName ) self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) end diff --git a/Moose Development/Moose/Detection.lua b/Moose Development/Moose/Detection.lua index acb86f8ac..b4a26d88d 100644 --- a/Moose Development/Moose/Detection.lua +++ b/Moose Development/Moose/Detection.lua @@ -3,9 +3,64 @@ -- === -- -- 1) @{Detection#DETECTION_BASE} class, extends @{Base#BASE} --- ===================================================== +-- ========================================================== -- The @{Detection#DETECTION_BASE} class defines the core functions to administer detected objects. --- Detected objects are grouped in SETS of UNITS. +-- +-- 1.1) DETECTION_BASE constructor +-- ------------------------------- +-- Construct a new DETECTION_BASE instance using the @{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: +-- +-- * @{Detection#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. +-- * @{Detection#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. +-- * @{Detection#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. +-- * @{Detection#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. +-- * @{Detection#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. +-- * @{Detection#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. +-- +-- 1.3) Obtain objects detected by DETECTION_BASE +-- ---------------------------------------------- +-- DETECTION_BASE builds @{Set}s of objects detected. These @{Set#SET_BASE}s can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSets}(). +-- The method will return a list (table) of @{Set#SET_BASE} objects. +-- +-- === +-- +-- 2) @{Detection#DETECTION_UNITGROUPS} class, extends @{Detection#DETECTION_BASE} +-- =============================================================================== +-- The @{Detection#DETECTION_UNITGROUPS} class will detect units within the battle zone for a FAC group, +-- and will build a list (table) of @{Set#SET_UNIT}s containing the @{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 @{Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Detection#DETECTION_UNITGROUPS}. +-- +-- Retrieve the DetectedUnitSets with the method @{Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Set#SET_UNIT}s. +-- To understand the amount of sets created, use the method @{Detection#DETECTION_BASE.GetDetectedSetCount}(). +-- If you want to obtain a specific set from the DetectedSets, use the method @{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 @{Detection#DETECTION_BASE.GetDetectionZones}(). +-- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). +-- If you want to obtain a specific zone from the DetectedZones, use the method @{Detection#DETECTION_BASE.GetDetectionZone}() with a given index. +-- +-- 1.4) Flare or Smoke detected units +-- ---------------------------------- +-- Use the methods @{Detection#DETECTION_UNITGROUPS.FlareDetectedUnits}() or @{Detection#DETECTION_UNITGROUPS.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 @{Detection#DETECTION_UNITGROUPS.FlareDetectedZones}() or @{Detection#DETECTION_UNITGROUPS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place. +-- +-- === -- -- @module Detection -- @author Mechanic : Concept & Testing @@ -17,146 +72,427 @@ -- @type DETECTION_BASE -- @field Group#GROUP FACGroup The GROUP in the Forward Air Controller role. -- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @field #DETECTION_BASE.DetectedUnitSets DetectedUnitSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectedZoneRange. --- @field #DETECTION_BASE.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. --- @extends Set#SET_BASE +-- @field #DETECTION_BASE.DetectedSets DetectedSets A list of @{Set#SET_BASE}s containing the objects in each set that were detected. The base class will not build the detected sets, but will leave that to the derived classes. +-- @extends Base#BASE DETECTION_BASE = { ClassName = "DETECTION_BASE", - DetectedUnitSets = {}, - DetectedUnits = {}, + DetectedSets = {}, + DetectedObjects = {}, FACGroup = nil, DetectionRange = nil, - DetectionZoneRange = nil, } ---- @type DETECTION_BASE.DetectedUnitSets --- @list +--- @type DETECTION_BASE.DetectedSets +-- @list --- @type DETECTION_BASE.DetectedZones --- @list +-- @list --- DETECTION constructor. -- @param #DETECTION_BASE self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. -- @return #DETECTION_BASE self -function DETECTION_BASE:New( FACGroup, DetectionRange, DetectionZoneRange ) +function DETECTION_BASE:New( FACGroup, DetectionRange ) -- Inherits from BASE local self = BASE:Inherit( self, BASE:New() ) self.FACGroup = FACGroup self.DetectionRange = DetectionRange - self.DetectionZoneRange = DetectionZoneRange - self.DetectionScheduler = SCHEDULER:New(self, self._DetectionScheduler, { self, "Detection" }, 10, 30, 0.2 ) + self:InitDetectVisual( false ) + self:InitDetectOptical( false ) + self:InitDetectRadar( false ) + self:InitDetectRWR( false ) + self:InitDetectIRST( false ) + self:InitDetectDLINK( false ) + + return self end ---- Form @{Set}s of detected @{Unit#UNIT}s in an array of @{Set#SET_UNIT}s. +--- 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 + +--- Gets the FAC group. +-- @param #DETECTION_BASE self +-- @return Group#GROUP self +function DETECTION_BASE:GetFACGroup() + self:F2() + + return self.FACGroup +end + +--- Get the detected @{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 Set#SET_BASE +function DETECTION_BASE:GetDetectedSet( Index ) + + local DetectionSet = self.DetectedSets[Index] + if DetectionSet then + return DetectionSet + end + + return nil +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 @{Unit#UNIT}s in an array of @{Set#SET_BASE}s. -- @param #DETECTION_BASE self function DETECTION_BASE:_DetectionScheduler( SchedulerName ) self:F2( { SchedulerName } ) - self.DetectedUnitSets = {} + self.DetectedObjects = {} + self.DetectedSets = {} + self.DetectedZones = {} if self.FACGroup:IsAlive() then local FACGroupName = self.FACGroup:GetName() - local FACDetectedTargets = self.FACGroup:GetDetectedTargets() + + local FACDetectedTargets = self.FACGroup:GetDetectedTargets( + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) for FACDetectedTargetID, FACDetectedTarget in pairs( FACDetectedTargets ) do - local FACObject = FACDetectedTarget.object + local FACObject = FACDetectedTarget.object -- DCSObject#Object self:T2( FACObject ) if FACObject and FACObject:isExist() and FACObject.id_ < 50000000 then - local FACDetectedUnit = UNIT:Find( FACObject ) - local FACDetectedUnitName = FACDetectedUnit:GetName() + local FACDetectedObjectName = FACObject:getName() - local FACDetectedUnitPositionVec3 = FACDetectedUnit:GetPointVec3() + local FACDetectedObjectPositionVec3 = FACObject:getPoint() local FACGroupPositionVec3 = self.FACGroup:GetPointVec3() - local Distance = ( ( FACDetectedUnitPositionVec3.x - FACGroupPositionVec3.x )^2 + - ( FACDetectedUnitPositionVec3.y - FACGroupPositionVec3.y )^2 + - ( FACDetectedUnitPositionVec3.z - FACGroupPositionVec3.z )^2 + + local Distance = ( ( FACDetectedObjectPositionVec3.x - FACGroupPositionVec3.x )^2 + + ( FACDetectedObjectPositionVec3.y - FACGroupPositionVec3.y )^2 + + ( FACDetectedObjectPositionVec3.z - FACGroupPositionVec3.z )^2 ) ^ 0.5 / 1000 - self:T( { FACGroupName, FACDetectedUnitName, Distance } ) + self:T( { FACGroupName, FACDetectedObjectName, Distance } ) if Distance <= self.DetectionRange then - if not self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = {} + if not self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = {} end - self.DetectedUnits[FACDetectedUnitName].DetectedUnit = UNIT:FindByName( FACDetectedUnitName ) - self.DetectedUnits[FACDetectedUnitName].Visible = FACDetectedTarget.visible - self.DetectedUnits[FACDetectedUnitName].Type = FACDetectedTarget.type - self.DetectedUnits[FACDetectedUnitName].Distance = FACDetectedTarget.distance + self.DetectedObjects[FACDetectedObjectName].Name = FACDetectedObjectName + self.DetectedObjects[FACDetectedObjectName].Visible = FACDetectedTarget.visible + self.DetectedObjects[FACDetectedObjectName].Type = FACDetectedTarget.type + self.DetectedObjects[FACDetectedObjectName].Distance = FACDetectedTarget.distance else -- if beyond the DetectionRange then nullify... - if self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = nil + if self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = nil end end end end + + self:T2( self.DetectedObjects ) - -- okay, now we have a list of detected unit names ... + -- okay, now we have a list of detected object names ... -- Sort the table based on distance ... - self:T( { "Sorting DetectedUnits table:", self.DetectedUnits } ) - table.sort( self.DetectedUnits, function( a, b ) return a.Distance < b.Distance end ) - self:T( { "Sorted Targets Table:", self.DetectedUnits } ) + self:T( { "Sorting DetectedObjects table:", self.DetectedObjects } ) + table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end ) + self:T( { "Sorted Targets Table:", self.DetectedObjects } ) - -- Now group the DetectedUnits table into SET_UNITs, evaluating the DetectionZoneRange. + -- Now group the DetectedObjects table into SET_BASEs, evaluating the DetectionZoneRange. - if self.DetectedUnits then - for DetectedUnitName, DetectedUnitData in pairs( self.DetectedUnits ) do - local DetectedUnit = DetectedUnitData.DetectedUnit -- Unit#UNIT - if DetectedUnit and DetectedUnit:IsAlive() then - self:T( DetectedUnit:GetName() ) - if #self.DetectedUnitSets == 0 then - self:T( { "Adding Unit Set #", 1 } ) - self.DetectedUnitSets[1] = {} - self.DetectedUnitSets[1].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[1].Set = SET_UNIT:New() - self.DetectedUnitSets[1].Set:AddUnit( DetectedUnit ) - else - local AddedToSet = false - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - self:T( "Detected Unit Set #" .. DetectedUnitSetID ) - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - if DetectedUnit:IsInZone( DetectedZone ) then - self:T( "Adding to Unit Set #" .. DetectedUnitSetID ) - self.DetectedUnitSets[DetectedUnitSetID].Set:AddUnit( DetectedUnit ) - AddedToSet = true - end - end - if AddedToSet == false then - self:T( "Adding new Unit Set #" .. #self.DetectedUnitSets+1 ) - self.DetectedUnitSets[#self.DetectedUnitSets+1] = {} - self.DetectedUnitSets[#self.DetectedUnitSets].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[#self.DetectedUnitSets].Set = SET_UNIT:New() - self.DetectedUnitSets[#self.DetectedUnitSets].Set:AddUnit( DetectedUnit ) - end - end - end - end + if self.DetectedObjects then + self:CreateDetectionSets() end - -- Now all the tests should have been build, now make some smoke and flares... - - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - self:T( "Detected Set #" .. DetectedUnitSetID ) - DetectedUnitSet:ForEachUnit( - --- @param Unit#UNIT DetectedUnit - function( DetectedUnit ) - self:T( DetectedUnit:GetName() ) + + end +end + +--- @type DETECTION_UNITGROUPS.DetectedSets +-- @list +-- + + +--- @type DETECTION_UNITGROUPS.DetectedZones +-- @list +-- + + +--- DETECTION_UNITGROUPS class +-- @type DETECTION_UNITGROUPS +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @field #DETECTION_UNITGROUPS.DetectedSets DetectedSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectionZoneRange. +-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. +-- @extends Detection#DETECTION_BASE +DETECTION_UNITGROUPS = { + ClassName = "DETECTION_UNITGROUPS", + DetectedZones = {}, +} + + + +--- DETECTION_UNITGROUPS constructor. +-- @param Detection#DETECTION_UNITGROUPS self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @return Detection#DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:New( FACGroup, DetectionRange, DetectionZoneRange ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( FACGroup, DetectionRange ) ) + self.DetectionZoneRange = DetectionZoneRange + + self:Schedule( 10, 30 ) + + return self +end + +--- Get the detected @{Zone#ZONE_UNIT}s. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones +function DETECTION_UNITGROUPS:GetDetectedZones() + + local DetectedZones = self.DetectedZones + return DetectedZones +end + +--- Get the amount of @{Zone#ZONE_UNIT}s with detected units. +-- @param #DETECTION_UNITGROUPS self +-- @return #number Count +function DETECTION_UNITGROUPS:GetDetectedZoneCount() + + local DetectedZoneCount = #self.DetectedZones + return DetectedZoneCount +end + +--- Get a SET of detected objects using a given numeric index. +-- @param #DETECTION_UNITGROUPS self +-- @param #number Index +-- @return Zone#ZONE_UNIT +function DETECTION_UNITGROUPS:GetDetectedZone( Index ) + + local DetectedZone = self.DetectedZones[Index] + if DetectedZone then + return DetectedZone + end + + return nil +end + +--- Smoke the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedUnits() + self:F2() + + self._SmokeDetectedUnits = true + return self +end + +--- Flare the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedUnits() + self:F2() + + self._FlareDetectedUnits = true + return self +end + +--- Smoke the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedZones() + self:F2() + + self._SmokeDetectedZones = true + return self +end + +--- Flare the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedZones() + self:F2() + + self._FlareDetectedZones = true + return self +end + + +--- Make a DetectionSet table. This function will be overridden in the derived clsses. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:CreateDetectionSets() + self:F2() + + for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do + self:T( DetectedUnitData.Name ) + local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT + if DetectedUnit and DetectedUnit:IsAlive() then + self:T( DetectedUnit:GetName() ) + if #self.DetectedSets == 0 then + self:T( { "Adding Unit Set #", 1 } ) + self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[1] = SET_UNIT:New() + self.DetectedSets[1]:AddUnit( DetectedUnit ) + else + local AddedToSet = false + for DetectedZoneIndex = 1, #self.DetectedZones do + self:T( "Detected Unit Set #" .. DetectedZoneIndex ) + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + if DetectedUnit:IsInZone( DetectedZone ) then + self:T( "Adding to Unit Set #" .. DetectedZoneIndex ) + DetectedUnitSet:AddUnit( DetectedUnit ) + AddedToSet = true + end + end + if AddedToSet == false then + local DetectedZoneIndex = #self.DetectedZones + 1 + self:T( "Adding new zone #" .. DetectedZoneIndex ) + self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New() + self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit ) + end + end + end + end + + -- Now all the tests should have been build, now make some smoke and flares... + + for DetectedZoneIndex = 1, #self.DetectedZones do + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + self:T( "Detected Set #" .. DetectedZoneIndex ) + DetectedUnitSet:ForEachUnit( + --- @param Unit#UNIT DetectedUnit + function( DetectedUnit ) + self:T( DetectedUnit:GetName() ) + if self._FlareDetectedUnits then DetectedUnit:FlareRed() end - ) + if self._SmokeDetectedUnits then + DetectedUnit:SmokeRed() + end + end + ) + if self._FlareDetectedZones then + DetectedZone:FlareZone( POINT_VEC3.SmokeColor.White, 30, math.random( 0,90 ) ) + end + if self._SmokeDetectedZones then DetectedZone:SmokeZone( POINT_VEC3.SmokeColor.White, 30 ) end end -end \ No newline at end of file + +end + + diff --git a/Moose Development/Moose/Escort.lua b/Moose Development/Moose/Escort.lua index 2a543e7c5..e03c871c9 100644 --- a/Moose Development/Moose/Escort.lua +++ b/Moose Development/Moose/Escort.lua @@ -557,7 +557,6 @@ function ESCORT:MenuReportTargets( Seconds ) self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, Seconds ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) return self @@ -779,7 +778,6 @@ function ESCORT._SwitchReportNearbyTargets( MenuParam ) if self.ReportTargets then if not self.ReportTargetsScheduler then - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, 30 ) end else @@ -856,16 +854,6 @@ function ESCORT._AttackTarget( MenuParam ) EscortGroup:OptionROEOpenFire() EscortGroup:OptionROTPassiveDefense() EscortGroup:SetState( EscortGroup, "Escort", self ) --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskAttackUnit( AttackUnit ), --- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -876,15 +864,6 @@ function ESCORT._AttackTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -915,16 +894,6 @@ function ESCORT._AssistTarget( MenuParam ) if EscortGroupAttack:IsAir() then EscortGroupAttack:OptionROEOpenFire() EscortGroupAttack:OptionROTVertical() --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskAttackUnit( AttackUnit ), --- EscortGroupAttack:TaskOrbitCircle( 500, 350 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -935,15 +904,6 @@ function ESCORT._AssistTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -1003,7 +963,6 @@ function ESCORT._ResumeMission( MenuParam ) table.remove( WayPoints, 1 ) end - --routines.scheduleFunction( EscortGroup.SetTask, {EscortGroup, EscortGroup:TaskRoute( WayPoints ) }, timer.getTime() + 1 ) SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) diff --git a/Moose Development/Moose/Event.lua b/Moose Development/Moose/Event.lua index 88f16e783..bcad4497f 100644 --- a/Moose Development/Moose/Event.lua +++ b/Moose Development/Moose/Event.lua @@ -465,7 +465,8 @@ function EVENT:OnPlayerLeaveUnit( EventFunction, EventSelf ) end - +--- @param #EVENT self +-- @param #EVENTDATA Event function EVENT:onEvent( Event ) self:F2( { _EVENTCODES[Event.id], Event } ) @@ -499,7 +500,7 @@ function EVENT:onEvent( Event ) Event.WeaponName = Event.Weapon:getTypeName() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end - self:E( { _EVENTCODES[Event.id], Event } ) + self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } ) for ClassName, EventData in pairs( self.Events[Event.id] ) do if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } ) diff --git a/Moose Development/Moose/FAC.lua b/Moose Development/Moose/FAC.lua new file mode 100644 index 000000000..554888549 --- /dev/null +++ b/Moose Development/Moose/FAC.lua @@ -0,0 +1,210 @@ +--- This module contains the FAC classes. +-- +-- === +-- +-- 1) @{Fac#FAC_BASE} class, extends @{Base#BASE} +-- ============================================== +-- The @{Fac#FAC_BASE} class defines the core functions to report detected objects to clients. +-- Reportings can be done in several manners, and it is up to the derived classes if FAC_BASE to model the reporting behaviour. +-- +-- 1.1) FAC_BASE constructor: +-- ---------------------------- +-- * @{Fac#FAC_BASE.New}(): Create a new FAC_BASE instance. +-- +-- 1.2) FAC_BASE reporting: +-- ------------------------ +-- Derived FAC_BASE classes will reports detected units using the method @{Fac#FAC_BASE.ReportDetected}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the reporting can be changed using the methods @{Fac#FAC_BASE.SetReportInterval}(). +-- To control how long a reporting message is displayed, use @{Fac#FAC_BASE.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Fac#FAC_BASE.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Reporting can be started and stopped using the methods @{Fac#FAC_BASE.StartReporting}() and @{Fac#FAC_BASE.StopReporting}() respectively. +-- If an ad-hoc report is requested, use the method @{Fac#FAC_BASE#ReportNow}(). +-- +-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. +-- +-- === +-- +-- 2) @{Fac#FAC_REPORTING} class, extends @{Fac#FAC_BASE} +-- ====================================================== +-- The @{Fac#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Fac#FAC_BASE} class. +-- +-- 2.1) FAC_REPORTING constructor: +-- ------------------------------- +-- The @{Fac#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance. +-- +-- === +-- +-- @module Fac +-- @author Mechanic, Prof_Hilactic, FlightControl : Concept & Testing +-- @author FlightControl : Design & Programming + + + +--- FAC_BASE class. +-- @type FAC_BASE +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends Base#BASE +FAC_BASE = { + ClassName = "FAC_BASE", + ClientSet = nil, + Detection = nil, +} + +--- FAC constructor. +-- @param #FAC_BASE self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_BASE self +function FAC_BASE:New( ClientSet, Detection ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) -- Fac#FAC_BASE + + self.ClientSet = ClientSet + self.Detection = Detection + + self:SetReportInterval( 60 ) + self:SetReportDisplayTime( 15 ) + + return self +end + +--- Set the reporting time interval. +-- @param #FAC_BASE self +-- @param #number ReportInterval The interval in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportInterval( ReportInterval ) + self:F2() + + self._ReportInterval = ReportInterval +end + + +--- Set the reporting message display time. +-- @param #FAC_BASE self +-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportDisplayTime( ReportDisplayTime ) + self:F2() + + self._ReportDisplayTime = ReportDisplayTime +end + +--- Get the reporting message display time. +-- @param #FAC_BASE self +-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. +function FAC_BASE:GetReportDisplayTime() + self:F2() + + return self._ReportDisplayTime +end + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_BASE self +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #FAC_BASE self +function FAC_BASE:ReportDetected( DetectedSets ) + self:F2() + + + +end + +--- Schedule the FAC reporting. +-- @param #FAC_BASE 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 #FAC_BASE self +function FAC_BASE:Schedule( DelayTime, ReportInterval ) + self:F2() + + self._ScheduleDelayTime = DelayTime + + self:SetReportInterval( ReportInterval ) + + self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "Fac" }, self._ScheduleDelayTime, self._ReportInterval ) + return self +end + +--- Report the detected @{Unit#UNIT}s detected within the @{DetectION#DETECTION_BASE} object to the @{Set#SET_CLIENT}s. +-- @param #FAC_BASE self +function FAC_BASE:_FacScheduler( SchedulerName ) + self:F2( { SchedulerName } ) + + self.ClientSet:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + if Client:IsAlive() then + local DetectedSets = self.Detection:GetDetectedSets() + return self:ReportDetected( Client, DetectedSets ) + end + end + ) + + return true +end + +-- FAC_REPORTING + +--- FAC_REPORTING class. +-- @type FAC_REPORTING +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends #FAC_BASE +FAC_REPORTING = { + ClassName = "FAC_REPORTING", +} + + +--- FAC_REPORTING constructor. +-- @param #FAC_REPORTING self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_REPORTING self +function FAC_REPORTING:New( ClientSet, Detection ) + + -- Inherits from FAC_BASE + local self = BASE:Inherit( self, FAC_BASE:New( ClientSet, Detection ) ) -- #FAC_REPORTING + + self:Schedule( 5, 60 ) + return self +end + + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_REPORTING self +-- @param Client#CLIENT Client The @{Client} object to where the report needs to go. +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. +function FAC_REPORTING:ReportDetected( Client, DetectedSets ) + self:F2( Client ) + + local DetectedMsg = {} + for DetectedUnitSetID, DetectedUnitSet in pairs( DetectedSets ) do + local UnitSet = DetectedUnitSet -- Set#SET_UNIT + local MT = {} -- Message Text + local UnitTypes = {} + for DetectedUnitID, DetectedUnitData in pairs( UnitSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Unit#UNIT + local UnitType = DetectedUnit:GetTypeName() + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + local MessageText = table.concat( MT, ", " ) + DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedUnitSetID .. ": " .. MessageText + end + local FACGroup = self.Detection:GetFACGroup() + FACGroup:MessageToClient( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Client ) + + return true +end + diff --git a/Moose Development/Moose/Group.lua b/Moose Development/Moose/Group.lua index 8399048c1..5792cad84 100644 --- a/Moose Development/Moose/Group.lua +++ b/Moose Development/Moose/Group.lua @@ -1,7 +1,7 @@ --- This module contains the GROUP class. -- --- 1) @{Group#GROUP} class, extends @{Base#BASE} --- ============================================= +-- 1) @{Group#GROUP} class, extends @{Controllable#CONTROLLABLE} +-- ============================================================= -- The @{Group#GROUP} class is a wrapper class to handle the DCS Group objects: -- -- * Support all DCS Group APIs. @@ -149,28 +149,18 @@ --- The GROUP class -- @type GROUP --- @extends Base#BASE --- @field DCSGroup#Group DCSGroup The DCS group class. +-- @extends Controllable#CONTROLLABLE -- @field #string GroupName The name of the group. GROUP = { ClassName = "GROUP", - GroupName = "", - GroupID = 0, - Controller = nil, - DCSGroup = nil, - WayPointFunctions = {}, } ---- A DCSGroup --- @type DCSGroup --- @field id_ The ID of the group in DCS - --- Create a new GROUP from a DCSGroup -- @param #GROUP self -- @param DCSGroup#Group GroupName The DCS Group name -- @return #GROUP self function GROUP:Register( GroupName ) - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName return self @@ -205,7 +195,7 @@ end --- Returns the DCS Group. -- @param #GROUP self -- @return DCSGroup#Group The DCS Group. -function GROUP:GetDCSGroup() +function GROUP:GetDCSObject() local DCSGroup = Group.getByName( self.GroupName ) if DCSGroup then @@ -223,7 +213,7 @@ end function GROUP:IsAlive() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupIsAlive = DCSGroup:isExist() @@ -241,7 +231,7 @@ end function GROUP:Destroy() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then for Index, UnitData in pairs( DCSGroup:getUnits() ) do @@ -260,7 +250,7 @@ end function GROUP:GetCategory() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() self:T3( GroupCategory ) @@ -276,7 +266,7 @@ end function GROUP:GetCategoryName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local CategoryNames = { [Group.Category.AIRPLANE] = "Airplane", @@ -300,7 +290,7 @@ end function GROUP:GetCoalition() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCoalition = DCSGroup:getCoalition() self:T3( GroupCoalition ) @@ -317,7 +307,7 @@ end function GROUP:GetCountry() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCountry = DCSGroup:getUnit(1):getCountry() self:T3( GroupCountry ) @@ -327,40 +317,6 @@ function GROUP:GetCountry() return nil end ---- Returns the name of the DCS Group. --- @param #GROUP self --- @return #string The DCS Group name. -function GROUP:GetName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupName = DCSGroup:getName() - self:T3( GroupName ) - return GroupName - end - - return nil -end - ---- Returns the DCS Group identifier. --- @param #GROUP self --- @return #number The identifier of the DCS Group. -function GROUP:GetID() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupID = DCSGroup:getID() - self:T3( GroupID ) - return GroupID - 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 @@ -369,7 +325,7 @@ end function GROUP:GetUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) @@ -389,7 +345,7 @@ end function GROUP:GetDCSUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) @@ -406,7 +362,7 @@ end -- @return #number The DCS Group size. function GROUP:GetSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupSize = DCSGroup:getSize() @@ -424,7 +380,7 @@ end -- @return #number The DCS Group initial size. function GROUP:GetInitialSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupInitialSize = DCSGroup:getInitialSize() @@ -440,7 +396,7 @@ end -- @return #table The UNITs wrappers. function GROUP:GetUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -461,7 +417,7 @@ end -- @return #table The DCS Units. function GROUP:GetDCSUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -472,117 +428,13 @@ function GROUP:GetDCSUnits() return nil end ---- Get the controller for the GROUP. --- @param #GROUP self --- @return DCSController#Controller -function GROUP:_GetController() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupController = DCSGroup:getController() - self:T3( GroupController ) - return GroupController - end - - return nil -end - - ---- Retrieve the group mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Group#GROUP:WayPointFunction} to define the hook functions for specific waypoints. --- Use the method @{Group@GROUP:WayPointExecute) to start the execution of the new mission plan. --- Note that when WayPointInitialize is called, the Mission of the group is RESTARTED! --- @param #GROUP self --- @param #table WayPoints If WayPoints is given, then use the route. --- @return #GROUP -function GROUP:WayPointInitialize( WayPoints ) - - if WayPoints then - self.WayPoints = WayPoints - else - self.WayPoints = self:GetTaskRoute() - end - - return self -end - - ---- Registers a waypoint function that will be executed when the group moves over the WayPoint. --- @param #GROUP 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 group moves over the waypoint. The waypoint function takes variable parameters. --- @return #GROUP -function GROUP: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 GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) - self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) - - local DCSTask - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) " - - if FunctionArguments and #FunctionArguments > 0 then - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )" - 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 group will be 1! --- @param #GROUP 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 #GROUP -function GROUP:WayPointExecute( 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 - --- Activates a GROUP. -- @param #GROUP self function GROUP:Activate() self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSGroup() ) - return self:GetDCSGroup() + trigger.action.activateGroup( self:GetDCSObject() ) + return self:GetDCSObject() end @@ -592,7 +444,7 @@ end function GROUP:GetTypeName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupTypeName = DCSGroup:getUnit(1):getTypeName() @@ -609,7 +461,7 @@ end function GROUP:GetCallsign() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCallSign = DCSGroup:getUnit(1):getCallsign() @@ -621,11 +473,14 @@ function GROUP:GetCallsign() end --- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. +-- @param #GROUP self -- @return DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. function GROUP:GetPointVec2() self:F2( self.GroupName ) - local GroupPointVec2 = self:GetUnit(1):GetPointVec2() + local UnitPoint = self:GetUnit(1) + UnitPoint:GetPointVec2() + local GroupPointVec2 = UnitPoint:GetPointVec2() self:T3( GroupPointVec2 ) return GroupPointVec2 end @@ -703,7 +558,7 @@ end function GROUP:IsAir() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER @@ -720,7 +575,7 @@ end function GROUP:IsHelicopter() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -737,7 +592,7 @@ end function GROUP:IsAirPlane() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -754,7 +609,7 @@ end function GROUP:IsGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -771,7 +626,7 @@ end function GROUP:IsShip() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -789,7 +644,7 @@ end function GROUP:AllOnGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local AllOnGroundResult = true @@ -814,7 +669,7 @@ end function GROUP:GetMaxVelocity() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local MaxVelocity = 0 @@ -853,1478 +708,6 @@ function GROUP:GetMaxHeight() end --- Tasks - ---- Popping current Task from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PopCurrentTask() - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:popTask() - return self - end - - return nil -end - ---- Pushing Task on the queue from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PushTask( DCSTask, WaitTime ) - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller:pushTask( DCSTask ) - - if WaitTime then - --routines.scheduleFunction( Controller.pushTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( 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 group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller.setTask( Controller, DCSTask ) - - if not WaitTime then - WaitTime = 1 - end - --routines.scheduleFunction( Controller.setTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) - - return self - end - - return nil -end - - ---- Return a condition section for a controlled task. --- @param #GROUP self --- @param DCSTime#Time time --- @param #string userFlag --- @param #boolean userFlagValue --- @param #string condition --- @param DCSTime#Time duration --- @param #number lastWayPoint --- return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#Task DCSTask --- @param #DCSStopCondition DCSStopCondition --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return #GROUP self -function GROUP:SetCommand( DCSCommand ) - self:F2( DCSCommand ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:setCommand( DCSCommand ) - return self - end - - return nil -end - ---- Perform a switch waypoint command --- @param #GROUP self --- @param #number FromWayPoint --- @param #number ToWayPoint --- @return DCSTask#Task -function GROUP:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) - self:F2( { FromWayPoint, ToWayPoint, Index } ) - - local CommandSwitchWayPoint = { - id = 'SwitchWaypoint', - params = { - fromWaypointIndex = FromWayPoint, - goToWaypointIndex = ToWayPoint, - }, - } - - self:T3( { CommandSwitchWayPoint } ) - return CommandSwitchWayPoint -end - ---- Perform stop route command --- @param #GROUP self --- @param #boolean StopRoute --- @return DCSTask#Task -function GROUP:CommandStopRoute( StopRoute, Index ) - self:F2( { StopRoute, Index } ) - - local CommandStopRoute = { - id = 'StopRoute', - params = { - value = StopRoute, - }, - } - - self:T3( { CommandStopRoute } ) - return CommandStopRoute -end - - --- TASKS FOR AIR GROUPS - - ---- (AIR) Attack a Group. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- AttackGroup = { - -- id = 'AttackGroup', - -- 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 = 'AttackGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- AttackUnit = { - -- id = 'AttackUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- } - -- } - - local DCSTask - DCSTask = { id = 'AttackUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon at the point on the ground. --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- Bombing = { --- id = 'Bombing', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'Bombing', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - 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 #GROUP self --- @param 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 #GROUP self -function GROUP:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.GroupName, 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 group at a specified alititude. --- @param #GROUP self --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #GROUP self -function GROUP:TaskOrbitCircle( Altitude, Speed ) - self:F2( { self.GroupName, Altitude, Speed } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupPoint = self:GetPointVec2() - return self:TaskOrbitCircleAtVec2( GroupPoint, Altitude, Speed ) - end - - return nil -end - - - ---- (AIR) Hold position at the current position of the first unit of the group. --- @param #GROUP self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #GROUP self -function GROUP:TaskHoldPosition() - self:F2( { self.GroupName } ) - - return self:TaskOrbitCircle( 30, 10 ) -end - - - - ---- (AIR) Attacking the map object (building, structure, e.t.c). --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- AttackMapObject = { --- id = 'AttackMapObject', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'AttackMapObject', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon on the runway. --- @param #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- BombingRunway = { --- id = 'BombingRunway', --- params = { --- runwayId = AirdromeId, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'BombingRunway', - params = { - point = Airbase:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Refueling from the nearest tanker. No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskRefueling() - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @param DCSTypes#Vec2 Point The point where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtVec2( Point, Duration ) - self:F2( { self.GroupName, 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 group at a @{Zone#ZONE_RADIUS). --- @param #GROUP self --- @param Zone#ZONE Zone The zone where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtZone( Zone, Duration, RandomPoint ) - self:F2( { self.GroupName, Zone, Duration, RandomPoint } ) - - local Point - if RandomPoint then - Point = Zone:GetRandomVec2() - else - Point = Zone:GetPointVec2() - end - - local DCSTask = self:TaskLandAtVec2( Point, Duration ) - - self:T3( DCSTask ) - return DCSTask -end - - - ---- (AIR) Following another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- If another group is on land the unit / group will orbit around. --- @param #GROUP self --- @param Group#GROUP FollowGroup The group to be followed. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFollow( FollowGroup, PointVec3, LastWaypointIndex ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex } ) - --- Follow = { --- id = 'Follow', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Escort another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- The unit / group will also protect that group from threats of specified types. --- @param #GROUP self --- @param Group#GROUP EscortGroup The group to be escorted. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @param #number EngagementDistanceMax Maximal distance from escorted group to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEscort( FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) - --- Escort = { --- id = 'Escort', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number, --- engagementDistMax = Distance, --- targetTypes = array of AttributeName, --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 The point to fire at. --- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFireAtPoint( PointVec2, Radius ) - self:F2( { self.GroupName, PointVec2, Radius } ) - - -- FireAtPoint = { - -- id = 'FireAtPoint', - -- params = { - -- point = Vec2, - -- radius = Distance, - -- } - -- } - - local DCSTask - DCSTask = { id = 'FireAtPoint', - params = { - point = PointVec2, - radius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Hold ground group from moving. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskHold() - self:F2( { self.GroupName } ) - --- Hold = { --- id = 'Hold', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Hold', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- TASKS FOR AIRBORNE AND GROUND UNITS/GROUPS - ---- (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Designation, Datalink } ) - --- FAC_AttackGroup = { --- id = 'FAC_AttackGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_AttackGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - --- EN-ROUTE TASKS FOR AIRBORNE GROUPS - ---- (AIR) Engaging targets of defined types. --- @param #GROUP self --- @param 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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) - self:F2( { self.GroupName, 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. --- @param DCSTypes#Distance Radius Radius of the zone. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) - self:F2( { self.GroupName, PointVec2, Radius, TargetTypes, Priority } ) - --- EngageTargetsInZone = { --- id = 'EngageTargetsInZone', --- params = { --- point = Vec2, --- zoneRadius = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargetsInZone', - params = { - point = PointVec2, - zoneRadius = Radius, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- EngageGroup = { - -- id = 'EngageGroup ', - -- 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 = 'EngageGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageUnit( AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- EngageUnit = { - -- id = 'EngageUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- priority = number, - -- } - -- } - - local DCSTask - DCSTask = { id = 'EngageUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskAWACS( ) - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskTanker( ) - self:F2( { self.GroupName } ) - --- Tanker = { --- id = 'Tanker', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Tanker', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for ground units/groups - ---- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEWR( ) - self:F2( { self.GroupName } ) - --- EWR = { --- id = 'EWR', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'EWR', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for airborne and ground units/groups - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) - --- FAC_EngageGroup = { --- id = 'FAC_EngageGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean, --- priority = number, --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_EngageGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - priority = Priority, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC( Radius, Priority ) - self:F2( { self.GroupName, 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 group to a Vec2 Point, wait for a defined duration and embark a group. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Duration The duration in seconds to wait. --- @param #GROUP EmbarkingGroup The group to be embarked. --- @return DCSTask#Task The DCS task structure -function GROUP:TaskEmbarking( Point, Duration, EmbarkingGroup ) - self:F2( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) - - local DCSTask - DCSTask = { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - groupsForEmbarking = { EmbarkingGroup.GroupID }, - 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 group when arrived within a defined Radius. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Radius The radius of the embarking zone around the Point. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEmbarkToTransport( Point, Radius ) - self:F2( { self.GroupName, Point, Radius } ) - - local DCSTask --DCSTask#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 #GROUP self --- @param #table TaskMission A table containing the mission task. --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param #table Points A table of route points. --- @return DCSTask#Task -function GROUP:TaskRoute( Points ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR + GROUND) Make the Group move to fly to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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 Group move to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec3() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.z - PointFrom.alt = GroupPoint.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 group to follow a given route. --- @param #GROUP self --- @param #table GoPoints A table of Route Points. --- @return #GROUP self -function GROUP:Route( GoPoints ) - self:F2( GoPoints ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Points = routines.utils.deepCopy( GoPoints ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } - local Controller = self:_GetController() - --Controller.setTask( Controller, MissionTask ) - --routines.scheduleFunction( Controller.setTask, { Controller, MissionTask}, timer.getTime() + 1 ) - SCHEDULER:New( Controller, Controller.setTask, { MissionTask }, 1 ) - return self - end - - return nil -end - - - ---- (AIR + GROUND) Route the group to a given zone. --- The group final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param 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 GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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:GetPointVec2() - 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 Group to an @{Airbase#AIRBASE} --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param Airbase#AIRBASE ReturnAirbase The @{Airbase#AIRBASE} to return to. --- @param #number Speed (optional) The speed. --- @return #string The route -function GROUP: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 DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - local GroupVelocity = self:GetMaxVelocity() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = GroupVelocity - - - local PointTo = {} - local AirbasePoint = ReturnAirbase:GetPointVec2() - - 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 - --- @param Group#GROUP self function GROUP:Respawn( Template ) @@ -2359,26 +742,6 @@ function GROUP:GetTemplate() end --- Commands - ---- Do Script command --- @param #GROUP self --- @param #string DoScript --- @return #DCSCommand -function GROUP:CommandDoScript( DoScript ) - - local DCSDoScript = { - id = "Script", - params = { - command = DoScript, - }, - } - - self:T3( DCSDoScript ) - return DCSDoScript -end - - --- Return the mission template of the group. -- @param #GROUP self -- @return #table The MissionTemplate @@ -2449,359 +812,6 @@ function GROUP:CopyRoute( Begin, End, Randomize, Radius ) end -function GROUP:GetDetectedTargets() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - return self:_GetController():getDetectedTargets() - end - - return nil -end - -function GROUP:IsTargetDetected( DCSObject ) - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP hold their weapons? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEHoldFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Holding weapons. --- @param Group#GROUP self --- @return Group#GROUP self -function GROUP:OptionROEHoldFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack returning on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEReturnFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Return fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEReturnFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack designated targets? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEOpenFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Openfire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEOpenFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack targets of opportunity? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEWeaponFreePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Weapon free. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEWeaponFree() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP ignore enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTNoReactionPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- No evasion on enemy threats. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTNoReaction() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade using passive defenses? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTPassiveDefensePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Evasion passive defense. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTPassiveDefense() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTEvadeFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTEvadeFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on fire using vertical manoeuvres? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTVerticalPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire using vertical manoeuvres. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTVertical() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 - -- Message APIs --- Returns a message for a coalition or a client. @@ -2812,7 +822,7 @@ end function GROUP:Message( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. self:GetTypeName() .. ")" ) end @@ -2828,7 +838,7 @@ end function GROUP:MessageToAll( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToAll() end @@ -2844,7 +854,7 @@ end function GROUP:MessageToRed( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToRed() end @@ -2860,7 +870,7 @@ end function GROUP:MessageToBlue( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToBlue() end @@ -2877,7 +887,7 @@ end function GROUP:MessageToClient( Message, Duration, Client ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToClient( Client ) end diff --git a/Moose Development/Moose/Identifiable.lua b/Moose Development/Moose/Identifiable.lua new file mode 100644 index 000000000..82ca95e15 --- /dev/null +++ b/Moose Development/Moose/Identifiable.lua @@ -0,0 +1,205 @@ +--- This module contains the IDENTIFIABLE class. +-- +-- 1) @{Identifiable#IDENTIFIABLE} class, extends @{Object#OBJECT} +-- =============================================================== +-- The @{Identifiable#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#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. +-- +-- 1.2) IDENTIFIABLE methods: +-- -------------------------- +-- The following methods can be used to identify an identifiable object: +-- +-- * @{Identifiable#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. +-- * @{Identifiable#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. +-- +-- +-- === +-- +-- @module Identifiable +-- @author FlightControl + +--- The IDENTIFIABLE class +-- @type IDENTIFIABLE +-- @extends 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 DCSIdentifiable#Identifiable IdentifiableName The DCS Identifiable name +-- @return #IDENTIFIABLE self +function IDENTIFIABLE:New( IdentifiableName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( IdentifiableName ) + self.IdentifiableName = IdentifiableName + return self +end + +--- Returns if the Identifiable is alive. +-- @param Identifiable#IDENTIFIABLE self +-- @return #boolean true if Identifiable is alive. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:IsAlive() + self:F2( 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#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#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 the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. +-- @param Identifiable#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#IDENTIFIABLE self +-- @return DCSCoalitionObject#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#IDENTIFIABLE self +-- @return 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#IDENTIFIABLE self +-- @return DCSIdentifiable#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 + + + + + + + + + diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index 13a60b6d3..1c2f3ffe6 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -2,6 +2,10 @@ Include.File( "Routines" ) Include.File( "Base" ) +Include.File( "Object" ) +Include.File( "Identifiable" ) +Include.File( "Positionable" ) +Include.File( "Controllable" ) Include.File( "Scheduler" ) Include.File( "Event" ) Include.File( "Menu" ) @@ -40,6 +44,7 @@ Include.File( "PatrolZone" ) Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) +Include.File( "FAC" ) -- The order of the declarations is important here. Don't touch it. diff --git a/Moose Development/Moose/Object.lua b/Moose Development/Moose/Object.lua new file mode 100644 index 000000000..05b8e2855 --- /dev/null +++ b/Moose Development/Moose/Object.lua @@ -0,0 +1,213 @@ +--- This module contains the OBJECT class. +-- +-- 1) @{Object#OBJECT} class, extends @{Base#BASE} +-- =========================================================== +-- The @{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: +-- +-- * @{Object#OBJECT.New}(): Create a OBJECT instance. +-- +-- 1.2) OBJECT methods: +-- -------------------------- +-- The following methods can be used to identify an Object object: +-- +-- * @{Object#OBJECT.GetID}(): Returns the ID of the Object object. +-- +-- === +-- +-- @module Object +-- @author FlightControl + +--- The OBJECT class +-- @type OBJECT +-- @extends 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 DCSObject#Object ObjectName The Object name +-- @return #OBJECT self +function OBJECT:New( ObjectName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( ObjectName ) + self.ObjectName = ObjectName + return self +end + + +--- Returns if the Object is alive. +-- @param Object#OBJECT self +-- @return #boolean true if Object is alive. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:IsAlive() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectIsAlive = DCSObject:isExist() + return ObjectIsAlive + end + + return false +end + + + + +--- Returns DCS Object object name. +-- The function provides access to non-activated objects too. +-- @param Object#OBJECT self +-- @return #string The name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectName = self.ObjectName + return ObjectName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the type name of the DCS Object. +-- @param Object#OBJECT self +-- @return #string The type name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetTypeName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectTypeName = DCSObject:getTypeName() + self:T3( ObjectTypeName ) + return ObjectTypeName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns the Object's callsign - the localized string. +-- @param Object#OBJECT self +-- @return #string The Callsign of the Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCallSign() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCallSign = DCSObject:getCallsign() + return ObjectCallSign + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the DCS Object category name as defined within the DCS Object Descriptor. +-- @param Object#OBJECT self +-- @return #string The DCS Object Category Name +function OBJECT:GetCategoryName() + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCategoryName = _CategoryName[ self:GetDesc().category ] + return ObjectCategoryName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns coalition of the Object. +-- @param Object#OBJECT self +-- @return DCSCoalitionObject#coalition.side The side of the coalition. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCoalition() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCoalition = DCSObject:getCoalition() + self:T3( ObjectCoalition ) + return ObjectCoalition + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns country of the Object. +-- @param Object#OBJECT self +-- @return DCScountry#country.id The country identifier. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCountry() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCountry = DCSObject:getCountry() + self:T3( ObjectCountry ) + return ObjectCountry + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + +--- Returns Object descriptor. Descriptor type depends on Object category. +-- @param Object#OBJECT self +-- @return DCSObject#Object.Desc The Object descriptor. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetDesc() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectDesc = DCSObject:getDesc() + self:T2( ObjectDesc ) + return ObjectDesc + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + + + + + + + diff --git a/Moose Development/Moose/Positionable.lua b/Moose Development/Moose/Positionable.lua new file mode 100644 index 000000000..82c824957 --- /dev/null +++ b/Moose Development/Moose/Positionable.lua @@ -0,0 +1,213 @@ +--- This module contains the POSITIONABLE class. +-- +-- 1) @{Positionable#POSITIONABLE} class, extends @{Identifiable#IDENTIFIABLE} +-- =========================================================== +-- The @{Positionable#POSITIONABLE} class is a wrapper class to handle the DCS Positionable objects: +-- +-- * Support all DCS Positionable APIs. +-- * Enhance with Positionable specific APIs not in the DCS Positionable API set. +-- * Manage the "state" of the DCS Positionable. +-- +-- 1.1) POSITIONABLE constructor: +-- ------------------------------ +-- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: +-- +-- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- 1.2) POSITIONABLE methods: +-- -------------------------- +-- The following methods can be used to identify an measurable object: +-- +-- * @{Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. +-- * @{Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. +-- +-- === +-- +-- @module Positionable +-- @author FlightControl + +--- The POSITIONABLE class +-- @type POSITIONABLE +-- @extends 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 DCSPositionable#Positionable PositionableName The DCS Positionable name +-- @return #POSITIONABLE self +function POSITIONABLE:New( PositionableName ) + local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) + + return self +end + +--- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Position The 3D position vectors of the DCS Positionable. +-- @return #nil The DCS 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 @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec2 The 2D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec2() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + + local PositionablePointVec2 = {} + PositionablePointVec2.x = PositionablePointVec3.x + PositionablePointVec2.y = PositionablePointVec3.z + + self:T2( PositionablePointVec2 ) + return PositionablePointVec2 + end + + return nil +end + + +--- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The 3D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + self:T3( PositionablePointVec3 ) + return PositionablePointVec3 + end + + return nil +end + +--- Returns the altitude of the DCS Positionable. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Distance The altitude of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetAltitude() + self:F2() + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPoint() --DCSTypes#Vec3 + return PositionablePointVec3.y + end + + return nil +end + +--- Returns if the Positionable is located above a runway. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if Positionable is above a runway. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:IsAboveRunway() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + + local PointVec2 = self:GetPointVec2() + local SurfaceType = land.getSurfaceType( PointVec2 ) + local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY + + self:T2( IsAboveRunway ) + return IsAboveRunway + end + + return nil +end + + + +--- Returns the DCS Positionable heading. +-- @param Positionable#POSITIONABLE self +-- @return #number The DCS Positionable 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 + self:T2( PositionableHeading ) + return PositionableHeading + end + end + + return nil +end + + +--- Returns true if the DCS Positionable is in the air. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if in the air. +-- @return #nil The DCS 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 DCS Positionable velocity vector. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The velocity vector +-- @return #nil The DCS 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 + + + diff --git a/Moose Development/Moose/Routines.lua b/Moose Development/Moose/Routines.lua index 5235f218b..f5f42d146 100644 --- a/Moose Development/Moose/Routines.lua +++ b/Moose Development/Moose/Routines.lua @@ -441,22 +441,6 @@ routines.getNorthCorrection = function(point) --gets the correction needed for end --- the main area -do - -- THE MAIN FUNCTION -- Accessed 100 times/sec. - routines.main = function() - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) --reschedule first in case of Lua error - ---------------------------------------------------------------------------------------------------------- - --area to add new stuff in - - routines.do_scheduled_functions() - end -- end of routines.main - - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) - -end - - do local idNum = 0 diff --git a/Moose Development/Moose/Scheduler.lua b/Moose Development/Moose/Scheduler.lua index d3d75fd95..9d6b66295 100644 --- a/Moose Development/Moose/Scheduler.lua +++ b/Moose Development/Moose/Scheduler.lua @@ -111,8 +111,10 @@ function SCHEDULER:_Scheduler() local ErrorHandler = function( errmsg ) env.info( "Error in SCHEDULER function:" .. errmsg ) - env.info( debug.traceback() ) - + if debug ~= nil then + env.info( debug.traceback() ) + end + return errmsg end diff --git a/Moose Development/Moose/Sead.lua b/Moose Development/Moose/Sead.lua index 489c1ecf9..25e9ceff2 100644 --- a/Moose Development/Moose/Sead.lua +++ b/Moose Development/Moose/Sead.lua @@ -50,7 +50,6 @@ function SEAD:EventShot( Event ) local SEADUnitName = Event.IniDCSUnitName local SEADWeapon = Event.Weapon -- Identify the weapon fired local SEADWeaponName = Event.WeaponName -- return weapon type - --trigger.action.outText( string.format("Alerte, depart missile " ..string.format(SEADWeaponName)), 20) --debug message -- 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 @@ -76,10 +75,10 @@ function SEAD:EventShot( Event ) local Skills = { "Average", "Good", "High", "Excellent" } _targetskill = Skills[ math.random(1,4) ] end - self:T( _targetskill ) -- debug message for skill check + 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)) ) --debug message + 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)) diff --git a/Moose Development/Moose/Set.lua b/Moose Development/Moose/Set.lua index a69b2c3c4..628d57b75 100644 --- a/Moose Development/Moose/Set.lua +++ b/Moose Development/Moose/Set.lua @@ -260,6 +260,15 @@ function SET_BASE:_Find( ObjectName ) end +--- Gets the Set. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:GetSet() + self:F2() + + return self.Set +end + --- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. -- @param #SET_BASE self -- @param #string ObjectName @@ -390,7 +399,7 @@ end -- @param #SET_BASE self -- @param Event#EVENTDATA Event function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F2( { Event } ) + self:F3( { Event } ) if Event.IniDCSUnit then local ObjectName, Object = self:FindInDatabase( Event ) @@ -446,7 +455,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen local function CoRoutine() local Count = 0 for ObjectID, Object in pairs( Set ) do - self:T2( Object ) + self:T3( Object ) if Function then if Function( unpack( FunctionArguments ), Object ) == true then IteratorFunction( Object, unpack( arg ) ) @@ -535,7 +544,7 @@ function SET_BASE:IsIncludeObject( Object ) return true end ---- Flushes the current SET_BASE contents in the log ... (for debug reasons). +--- 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() @@ -1156,7 +1165,6 @@ end function SET_UNIT:FindInDatabase( Event ) self:F3( { Event } ) - self:E( { Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] } ) return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end diff --git a/Moose Development/Moose/Static.lua b/Moose Development/Moose/Static.lua index 76e385b57..6833cf646 100644 --- a/Moose Development/Moose/Static.lua +++ b/Moose Development/Moose/Static.lua @@ -1,7 +1,7 @@ --- This module contains the STATIC class. -- --- 1) @{Static#STATIC} class, extends @{Unit#UNIT} --- =============================================== +-- 1) @{Static#STATIC} class, extends @{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 @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: @@ -38,7 +38,7 @@ --- The STATIC class -- @type STATIC --- @extends Unit#UNIT +-- @extends Positionable#POSITIONABLE STATIC = { ClassName = "STATIC", } @@ -62,10 +62,7 @@ function STATIC:FindByName( StaticName ) end function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, UNIT:Register( StaticName ) ) - - self:F( StaticName ) - + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) return self end diff --git a/Moose Development/Moose/Unit.lua b/Moose Development/Moose/Unit.lua index 744336e03..32b4d7bb2 100644 --- a/Moose Development/Moose/Unit.lua +++ b/Moose Development/Moose/Unit.lua @@ -1,7 +1,7 @@ --- This module contains the UNIT class. -- --- 1) @{Unit#UNIT} class, extends @{Base#BASE} --- =========================================== +-- 1) @{Unit#UNIT} class, extends @{Controllable#CONTROLLABLE} +-- =========================================================== -- The @{Unit#UNIT} class is a wrapper class to handle the DCS Unit objects: -- -- * Support all DCS Unit APIs. @@ -74,18 +74,11 @@ --- The UNIT class -- @type UNIT --- @extends Base#BASE +-- @extends Controllable#CONTROLLABLE -- @field #UNIT.FlareColor FlareColor -- @field #UNIT.SmokeColor SmokeColor UNIT = { ClassName="UNIT", - CategoryName = { - [Unit.Category.AIRPLANE] = "Airplane", - [Unit.Category.HELICOPTER] = "Helicoper", - [Unit.Category.GROUND_UNIT] = "Ground Unit", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - }, FlareColor = { Green = trigger.flareColor.Green, Red = trigger.flareColor.Red, @@ -120,13 +113,10 @@ UNIT = { --- Create a new UNIT from DCSUnit. -- @param #UNIT self --- @param DCSUnit#Unit DCSUnit --- @param Database#DATABASE Database +-- @param #string UnitName The name of the DCS unit. -- @return Unit#UNIT function UNIT:Register( UnitName ) - - local self = BASE:Inherit( self, BASE:New() ) - self:F2( UnitName ) + local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) self.UnitName = UnitName return self end @@ -154,7 +144,10 @@ function UNIT:FindByName( UnitName ) return UnitFound end -function UNIT:GetDCSUnit() + +--- @param #UNIT self +-- @return DCSUnit#Unit +function UNIT:GetDCSObject() local DCSUnit = Unit.getByName( self.UnitName ) @@ -165,78 +158,8 @@ function UNIT:GetDCSUnit() return nil end ---- Returns coalition of the Unit. --- @param Unit#UNIT self --- @return DCSCoalitionObject#coalition.side The side of the coalition. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCoalition() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCoalition = DCSUnit:getCoalition() - self:T3( UnitCoalition ) - return UnitCoalition - end - - return nil -end - ---- Returns country of the Unit. --- @param Unit#UNIT self --- @return DCScountry#country.id The country identifier. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCountry() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCountry = DCSUnit:getCountry() - self:T3( UnitCountry ) - return UnitCountry - end - - return nil -end - - ---- Returns DCS Unit object name. --- The function provides access to non-activated units too. --- @param Unit#UNIT self --- @return #string The name of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitName = self.UnitName - return UnitName - end - - return nil -end ---- Returns if the unit is alive. --- @param Unit#UNIT self --- @return #boolean true if Unit is alive. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAlive() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitIsAlive = DCSUnit:isExist() - return UnitIsAlive - end - - return false -end --- Returns if the unit is activated. -- @param Unit#UNIT self @@ -245,7 +168,7 @@ end function UNIT:IsActive() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -256,30 +179,25 @@ function UNIT:IsActive() return nil end ---- Returns if the unit is located above a runway. +--- Returns the Unit's callsign - the localized string. -- @param Unit#UNIT self --- @return #boolean true if Unit is above a runway. +-- @return #string The Callsign of the Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAboveRunway() +function UNIT:GetCallSign() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - - local PointVec2 = self:GetPointVec2() - local SurfaceType = land.getSurfaceType( PointVec2 ) - local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - - self:T2( IsAboveRunway ) - return IsAboveRunway + 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#UNIT self -- @return #string Player Name @@ -287,7 +205,7 @@ end function UNIT:GetPlayerName() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -301,23 +219,6 @@ function UNIT:GetPlayerName() return nil end ---- Returns the unit's unique identifier. --- @param Unit#UNIT self --- @return DCSUnit#Unit.ID Unit ID --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetID() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitID = DCSUnit:getID() - return UnitID - 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. @@ -328,7 +229,7 @@ end function UNIT:GetNumber() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitNumber = DCSUnit:getNumber() @@ -345,7 +246,7 @@ end function UNIT:GetGroup() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) @@ -356,69 +257,23 @@ function UNIT:GetGroup() end ---- Returns the unit's callsign - the localized string. +-- 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#UNIT self --- @return #string The Callsign of the Unit. +-- @return #string The name of the DCS Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCallSign() - self:F2( self.UnitName ) +function UNIT:GetPrefix() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitCallSign = DCSUnit:getCallsign() - return UnitCallSign - end - - return nil -end - ---- Returns the unit's health. Dead units has health <= 1.0. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife = DCSUnit:getLife() - return UnitLife - end - - return nil -end - ---- Returns the Unit's initial health. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife0 = DCSUnit:getLife0() - return UnitLife0 - end - - return 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#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:GetDCSUnit() - - if DCSUnit then - local UnitFuel = DCSUnit:getFuel() - return UnitFuel + local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) + self:T3( UnitPrefix ) + return UnitPrefix end return nil @@ -431,7 +286,7 @@ end function UNIT:GetAmmo() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitAmmo = DCSUnit:getAmmo() @@ -448,7 +303,7 @@ end function UNIT:GetSensors() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitSensors = DCSUnit:getSensors() @@ -472,7 +327,7 @@ end function UNIT:GetRadar() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() @@ -482,63 +337,52 @@ function UNIT:GetRadar() return nil, nil end --- Need to add here functions to check if radar is on and which object etc. - ---- Returns unit descriptor. Descriptor type depends on unit category. +--- 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#UNIT self --- @return DCSUnit#Unit.Desc The Unit descriptor. +-- @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:GetDesc() +function UNIT:GetFuel() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitDesc = DCSUnit:getDesc() - self:T2( UnitDesc ) - return UnitDesc + local UnitFuel = DCSUnit:getFuel() + return UnitFuel end - self:E( "Unit " .. self.UnitName .. "not found!" ) return nil end - ---- Returns the type name of the DCS Unit. +--- Returns the unit's health. Dead units has health <= 1.0. -- @param Unit#UNIT self --- @return #string The type name of the DCS Unit. +-- @return #number The Unit's health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetTypeName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() +function UNIT:GetLife() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitTypeName = DCSUnit:getTypeName() - self:T3( UnitTypeName ) - return UnitTypeName + local UnitLife = DCSUnit:getLife() + return UnitLife end - - return nil + + return nil end - - ---- 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. +--- Returns the Unit's initial health. -- @param Unit#UNIT self --- @return #string The name of the DCS Unit. +-- @return #number The Unit's initial health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPrefix() - self:F2( self.UnitName ) +function UNIT:GetLife0() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix + local UnitLife0 = DCSUnit:getLife0() + return UnitLife0 end return nil @@ -546,83 +390,6 @@ end ---- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec2 The 2D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec2() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - - local UnitPointVec2 = {} - UnitPointVec2.x = UnitPointVec3.x - UnitPointVec2.y = UnitPointVec3.z - - self:T2( UnitPointVec2 ) - return UnitPointVec2 - end - - return nil -end - - ---- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The 3D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - self:T3( UnitPointVec3 ) - return UnitPointVec3 - end - - return nil -end - ---- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Position The 3D position vectors of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPositionVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPosition = DCSUnit:getPosition() - self:T3( UnitPosition ) - return UnitPosition - end - - return nil -end - ---- Returns the DCS Unit velocity vector. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The velocity vector --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetVelocity() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitVelocityVec3 = DCSUnit:getVelocity() - self:T3( UnitVelocityVec3 ) - return UnitVelocityVec3 - end - - return nil -end -- Is functions @@ -660,40 +427,6 @@ function UNIT:IsNotInZone( Zone ) end end ---- Returns true if the DCS Unit is in the air. --- @param Unit#UNIT self --- @return #boolean true if in the air. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:InAir() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitInAir = DCSUnit:inAir() - self:T3( UnitInAir ) - return UnitInAir - end - - return nil -end - ---- Returns the altitude of the DCS Unit. --- @param Unit#UNIT self --- @return DCSTypes#Distance The altitude of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetAltitude() - self:F2() - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPoint() --DCSTypes#Vec3 - return UnitPointVec3.y - end - - return nil -end --- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. -- @param Unit#UNIT self @@ -704,7 +437,7 @@ end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitPos = self:GetPointVec3() @@ -722,41 +455,6 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) return nil end ---- Returns the DCS Unit category name as defined within the DCS Unit Descriptor. --- @param Unit#UNIT self --- @return #string The DCS Unit Category Name -function UNIT:GetCategoryName() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCategoryName = self.CategoryName[ self:GetDesc().category ] - return UnitCategoryName - end - - return nil -end - ---- Returns the DCS Unit heading. --- @param Unit#UNIT self --- @return #number The DCS Unit heading -function UNIT:GetHeading() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - - local UnitPosition = DCSUnit:getPosition() - if UnitPosition then - local UnitHeading = math.atan2( UnitPosition.x.z, UnitPosition.x.x ) - if UnitHeading < 0 then - UnitHeading = UnitHeading + 2 * math.pi - end - self:T2( UnitHeading ) - return UnitHeading - end - end - - return nil -end --- Signal a flare at the position of the UNIT. diff --git a/Moose Development/Moose/Zone.lua b/Moose Development/Moose/Zone.lua index 5deecb865..9bb906a90 100644 --- a/Moose Development/Moose/Zone.lua +++ b/Moose Development/Moose/Zone.lua @@ -490,33 +490,34 @@ 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 DCSTypes#Vec2 PointVec2 The location to test. -- @return #boolean true if the location is within the zone. function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 ) self:F2( PointVec2 ) - local i - local j - local c = false + local Next + local Prev + local InPolygon = false - i = 1 - j = #self.Polygon + Next = 1 + Prev = #self.Polygon - while i < #self.Polygon do - j = i - i = i + 1 - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) - if ( ( ( self.Polygon[i].y > PointVec2.y ) ~= ( self.Polygon[j].y > PointVec2.y ) ) and - ( PointVec2.x < ( self.Polygon[j].x - self.Polygon[i].x ) * ( PointVec2.y - self.Polygon[i].y ) / ( self.Polygon[j].y - self.Polygon[i].y ) + self.Polygon[i].x ) + while Next <= #self.Polygon do + self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) + if ( ( ( self.Polygon[Next].y > PointVec2.y ) ~= ( self.Polygon[Prev].y > PointVec2.y ) ) and + ( PointVec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( PointVec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) ) then - c = not c + InPolygon = not InPolygon end - self:T2( { "c = ", c } ) + self:T2( { InPolygon = InPolygon } ) + Prev = Next + Next = Next + 1 end - self:T( { "c = ", c } ) - return c + self:T( { InPolygon = InPolygon } ) + return InPolygon end --- Define a random @{DCSTypes#Vec2} within the zone. diff --git a/Moose Mission Setup/Moose Create Dynamic/Moose_Dynamic_Loader.lua b/Moose Mission Setup/Moose Create Dynamic/Moose_Dynamic_Loader.lua index 8c3b6bdf7..f0bd89564 100644 --- a/Moose Mission Setup/Moose Create Dynamic/Moose_Dynamic_Loader.lua +++ b/Moose Mission Setup/Moose Create Dynamic/Moose_Dynamic_Loader.lua @@ -3,25 +3,13 @@ local base = _G Include = {} -Include.Path = function() - local str = debug.getinfo(2, "S").source - return str:match("(.*/)"):sub(1,-2):gsub("\\","/") -end - Include.File = function( IncludeFile ) 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 - env.info( "Include:" .. IncludeFile .. " from " .. Include.MissionPath ) - local f = assert( base.loadfile( Include.MissionPath .. IncludeFile .. ".lua" ) ) - if f == nil then - error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) - else - env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath ) - return f() - end + error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) else env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) return f() @@ -30,10 +18,8 @@ Include.File = function( IncludeFile ) end Include.ProgramPath = "Scripts/Moose/" -Include.MissionPath = Include.Path() env.info( "Include.ProgramPath = " .. Include.ProgramPath) -env.info( "Include.MissionPath = " .. Include.MissionPath) Include.Files = {} 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 96327a527..7f30d885d 100644 --- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua +++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20160622_1015' ) +env.info( 'Moose Generation Timestamp: 20160626_0740' ) local base = _G Include = {} @@ -450,22 +450,6 @@ routines.getNorthCorrection = function(point) --gets the correction needed for end --- the main area -do - -- THE MAIN FUNCTION -- Accessed 100 times/sec. - routines.main = function() - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) --reschedule first in case of Lua error - ---------------------------------------------------------------------------------------------------------- - --area to add new stuff in - - routines.do_scheduled_functions() - end -- end of routines.main - - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) - -end - - do local idNum = 0 @@ -2969,7 +2953,7 @@ end -- @param Arguments A #table or any field. function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -2998,7 +2982,7 @@ end -- @param Arguments A #table or any field. function BASE:F( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3014,7 +2998,7 @@ end -- @param Arguments A #table or any field. function BASE:F2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3029,7 +3013,7 @@ end -- @param Arguments A #table or any field. function BASE:F3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3044,7 +3028,7 @@ end -- @param Arguments A #table or any field. function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -3073,7 +3057,7 @@ end -- @param Arguments A #table or any field. function BASE:T( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3089,7 +3073,7 @@ end -- @param Arguments A #table or any field. function BASE:T2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3104,7 +3088,7 @@ end -- @param Arguments A #table or any field. function BASE:T3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3119,25 +3103,2846 @@ end -- @param Arguments A #table or any field. function BASE:E( Arguments ) - 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 ) ) ) + 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 OBJECT class. +-- +-- 1) @{Object#OBJECT} class, extends @{Base#BASE} +-- =========================================================== +-- The @{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: +-- +-- * @{Object#OBJECT.New}(): Create a OBJECT instance. +-- +-- 1.2) OBJECT methods: +-- -------------------------- +-- The following methods can be used to identify an Object object: +-- +-- * @{Object#OBJECT.GetID}(): Returns the ID of the Object object. +-- +-- === +-- +-- @module Object +-- @author FlightControl + +--- The OBJECT class +-- @type OBJECT +-- @extends 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 DCSObject#Object ObjectName The Object name +-- @return #OBJECT self +function OBJECT:New( ObjectName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( ObjectName ) + self.ObjectName = ObjectName + return self +end + + +--- Returns if the Object is alive. +-- @param Object#OBJECT self +-- @return #boolean true if Object is alive. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:IsAlive() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectIsAlive = DCSObject:isExist() + return ObjectIsAlive + end + + return false +end + + + + +--- Returns DCS Object object name. +-- The function provides access to non-activated objects too. +-- @param Object#OBJECT self +-- @return #string The name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectName = self.ObjectName + return ObjectName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the type name of the DCS Object. +-- @param Object#OBJECT self +-- @return #string The type name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetTypeName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectTypeName = DCSObject:getTypeName() + self:T3( ObjectTypeName ) + return ObjectTypeName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns the Object's callsign - the localized string. +-- @param Object#OBJECT self +-- @return #string The Callsign of the Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCallSign() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCallSign = DCSObject:getCallsign() + return ObjectCallSign + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the DCS Object category name as defined within the DCS Object Descriptor. +-- @param Object#OBJECT self +-- @return #string The DCS Object Category Name +function OBJECT:GetCategoryName() + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCategoryName = _CategoryName[ self:GetDesc().category ] + return ObjectCategoryName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns coalition of the Object. +-- @param Object#OBJECT self +-- @return DCSCoalitionObject#coalition.side The side of the coalition. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCoalition() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCoalition = DCSObject:getCoalition() + self:T3( ObjectCoalition ) + return ObjectCoalition + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns country of the Object. +-- @param Object#OBJECT self +-- @return DCScountry#country.id The country identifier. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCountry() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCountry = DCSObject:getCountry() + self:T3( ObjectCountry ) + return ObjectCountry + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + +--- Returns Object descriptor. Descriptor type depends on Object category. +-- @param Object#OBJECT self +-- @return DCSObject#Object.Desc The Object descriptor. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetDesc() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectDesc = DCSObject:getDesc() + self:T2( ObjectDesc ) + return ObjectDesc + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + + + + + + + +--- This module contains the IDENTIFIABLE class. +-- +-- 1) @{Identifiable#IDENTIFIABLE} class, extends @{Object#OBJECT} +-- =============================================================== +-- The @{Identifiable#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#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. +-- +-- 1.2) IDENTIFIABLE methods: +-- -------------------------- +-- The following methods can be used to identify an identifiable object: +-- +-- * @{Identifiable#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. +-- * @{Identifiable#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. +-- +-- +-- === +-- +-- @module Identifiable +-- @author FlightControl + +--- The IDENTIFIABLE class +-- @type IDENTIFIABLE +-- @extends 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 DCSIdentifiable#Identifiable IdentifiableName The DCS Identifiable name +-- @return #IDENTIFIABLE self +function IDENTIFIABLE:New( IdentifiableName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( IdentifiableName ) + self.IdentifiableName = IdentifiableName + return self +end + +--- Returns if the Identifiable is alive. +-- @param Identifiable#IDENTIFIABLE self +-- @return #boolean true if Identifiable is alive. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:IsAlive() + self:F2( 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#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#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 the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. +-- @param Identifiable#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#IDENTIFIABLE self +-- @return DCSCoalitionObject#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#IDENTIFIABLE self +-- @return 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#IDENTIFIABLE self +-- @return DCSIdentifiable#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 + + + + + + + + + +--- This module contains the POSITIONABLE class. +-- +-- 1) @{Positionable#POSITIONABLE} class, extends @{Identifiable#IDENTIFIABLE} +-- =========================================================== +-- The @{Positionable#POSITIONABLE} class is a wrapper class to handle the DCS Positionable objects: +-- +-- * Support all DCS Positionable APIs. +-- * Enhance with Positionable specific APIs not in the DCS Positionable API set. +-- * Manage the "state" of the DCS Positionable. +-- +-- 1.1) POSITIONABLE constructor: +-- ------------------------------ +-- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: +-- +-- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- 1.2) POSITIONABLE methods: +-- -------------------------- +-- The following methods can be used to identify an measurable object: +-- +-- * @{Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. +-- * @{Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. +-- +-- === +-- +-- @module Positionable +-- @author FlightControl + +--- The POSITIONABLE class +-- @type POSITIONABLE +-- @extends 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 DCSPositionable#Positionable PositionableName The DCS Positionable name +-- @return #POSITIONABLE self +function POSITIONABLE:New( PositionableName ) + local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) + + return self +end + +--- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Position The 3D position vectors of the DCS Positionable. +-- @return #nil The DCS 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 @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec2 The 2D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec2() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + + local PositionablePointVec2 = {} + PositionablePointVec2.x = PositionablePointVec3.x + PositionablePointVec2.y = PositionablePointVec3.z + + self:T2( PositionablePointVec2 ) + return PositionablePointVec2 + end + + return nil +end + + +--- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The 3D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + self:T3( PositionablePointVec3 ) + return PositionablePointVec3 + end + + return nil +end + +--- Returns the altitude of the DCS Positionable. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Distance The altitude of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetAltitude() + self:F2() + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPoint() --DCSTypes#Vec3 + return PositionablePointVec3.y + end + + return nil +end + +--- Returns if the Positionable is located above a runway. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if Positionable is above a runway. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:IsAboveRunway() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + + local PointVec2 = self:GetPointVec2() + local SurfaceType = land.getSurfaceType( PointVec2 ) + local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY + + self:T2( IsAboveRunway ) + return IsAboveRunway + end + + return nil +end + + + +--- Returns the DCS Positionable heading. +-- @param Positionable#POSITIONABLE self +-- @return #number The DCS Positionable 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 + self:T2( PositionableHeading ) + return PositionableHeading + end + end + + return nil +end + + +--- Returns true if the DCS Positionable is in the air. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if in the air. +-- @return #nil The DCS 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 DCS Positionable velocity vector. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The velocity vector +-- @return #nil The DCS 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 + + + +--- This module contains the CONTROLLABLE class. +-- +-- 1) @{Controllable#CONTROLLABLE} class, extends @{Positionable#POSITIONABLE} +-- =========================================================== +-- The @{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 @{Controllable#CONTROLLABLE.PushTask} or @{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 @{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 +-- @author FlightControl + +--- The CONTROLLABLE class +-- @type CONTROLLABLE +-- @extends Positionable#POSITIONABLE +-- @field DCSControllable#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 DCSControllable#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 + return self +end + +-- DCS Controllable methods support. + +--- Get the controller for the CONTROLLABLE. +-- @param #CONTROLLABLE self +-- @return 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 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 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 + SCHEDULER:New( 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 Controllable#CONTROLLABLE self +function CONTROLLABLE:SetTask( DCSTask, WaitTime ) + self:F2( { DCSTask } ) + + 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.setTask( Controller, DCSTask ) + + if not WaitTime then + WaitTime = 1 + end + SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) + + return self + end + + return nil +end + + +--- Return a condition section for a controlled task. +-- @param #CONTROLLABLE self +-- @param DCSTime#Time time +-- @param #string userFlag +-- @param #boolean userFlagValue +-- @param #string condition +-- @param DCSTime#Time duration +-- @param #number lastWayPoint +-- return DCSTask#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 DCSTask#Task DCSTask +-- @param #DCSStopCondition DCSStopCondition +-- @return DCSTask#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 DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} +-- @return DCSTask#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 DCSCommand#Command DCSCommand +-- @return DCSTask#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 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 DCSTask#Task +function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) + self:F2( { FromWayPoint, ToWayPoint, Index } ) + + 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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackControllable( AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- AttackControllable = { + -- id = 'AttackControllable', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 = { + unitId = AttackUnit:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + attackQtyLimit = AttackQtyLimit, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Delivering weapon at the point on the ground. +-- @param #CONTROLLABLE self +-- @param DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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:GetPointVec2() + 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 DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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 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 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 DCSTask#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 DCSTask#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 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 @{Zone#ZONE_RADIUS). +-- @param #CONTROLLABLE self +-- @param 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:GetPointVec2() + 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 Controllable#CONTROLLABLE FollowControllable The controllable to be followed. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFollow( FollowControllable, PointVec3, LastWaypointIndex ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex } ) + +-- Follow = { +-- id = 'Follow', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEscort( FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) + +-- Escort = { +-- id = 'Escort', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number, +-- engagementDistMax = Distance, +-- targetTypes = array of AttributeName, +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 DCSTypes#Vec2 PointVec2 The point to fire at. +-- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFireAtPoint( PointVec2, Radius ) + self:F2( { self.ControllableName, PointVec2, Radius } ) + + -- FireAtPoint = { + -- id = 'FireAtPoint', + -- params = { + -- point = Vec2, + -- radius = Distance, + -- } + -- } + + local DCSTask + DCSTask = { id = 'FireAtPoint', + params = { + point = PointVec2, + radius = Radius, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (GROUND) Hold ground controllable from moving. +-- @param #CONTROLLABLE self +-- @return DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFAC_AttackControllable( AttackControllable, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Designation, Datalink } ) + +-- FAC_AttackControllable = { +-- id = 'FAC_AttackControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_AttackControllable', + params = { + controllableId = AttackControllable:GetID(), + weaponType = WeaponType, + designation = Designation, + datalink = Datalink, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +-- EN-ROUTE TASKS FOR AIRBORNE CONTROLLABLES + +--- (AIR) Engaging targets of defined types. +-- @param #CONTROLLABLE self +-- @param 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 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 DCSTask#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 DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. +-- @param DCSTypes#Distance Radius Radius of the zone. +-- @param 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) + self:F2( { self.ControllableName, PointVec2, Radius, TargetTypes, Priority } ) + +-- EngageTargetsInZone = { +-- id = 'EngageTargetsInZone', +-- params = { +-- point = Vec2, +-- zoneRadius = Distance, +-- targetTypes = array of AttributeName, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'EngageTargetsInZone', + params = { + point = PointVec2, + 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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageControllable( AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- EngageControllable = { + -- id = 'EngageControllable ', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 DCSTask#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 DCSTask#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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskFAC_EngageControllable( AttackControllable, Priority, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Priority, Designation, Datalink } ) + +-- FAC_EngageControllable = { +-- id = 'FAC_EngageControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean, +-- priority = number, +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_EngageControllable', + params = { + controllableId = AttackControllable: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 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 DCSTask#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 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 DCSTask#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 DCSTypes#Vec2 Point The point where to wait. +-- @param #number Radius The radius of the embarking zone around the Point. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) + self:F2( { self.ControllableName, Point, Radius } ) + + local DCSTask --DCSTask#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 DCSTask#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 DCSTask#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 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 ):GetPointVec2() + + 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 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 ControllablePoint = self:GetUnit( 1 ):GetPointVec3() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.z + PointFrom.alt = ControllablePoint.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 ) + SCHEDULER:New( 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 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:GetPointVec2() + + 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:GetPointVec2() + 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 @{Airbase#AIRBASE} +-- A speed can be given in km/h. +-- A given formation can be given. +-- @param #CONTROLLABLE self +-- @param Airbase#AIRBASE ReturnAirbase The @{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:GetPointVec2() + 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:GetPointVec2() + + 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 @{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 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 Controllable#CONTROLLABLE self +-- @return 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 @{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 ) + + if WayPoints then + self.WayPoints = WayPoints + else + self.WayPoints = self:GetTaskRoute() + end + + return self +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 = CONTROLLABLE: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 ) + + 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 + + --- This module contains the SCHEDULER class. -- -- 1) @{Scheduler#SCHEDULER} class, extends @{Base#BASE} @@ -3251,8 +6056,10 @@ function SCHEDULER:_Scheduler() local ErrorHandler = function( errmsg ) env.info( "Error in SCHEDULER function:" .. errmsg ) - env.info( debug.traceback() ) - + if debug ~= nil then + env.info( debug.traceback() ) + end + return errmsg end @@ -3771,7 +6578,8 @@ function EVENT:OnPlayerLeaveUnit( EventFunction, EventSelf ) end - +--- @param #EVENT self +-- @param #EVENTDATA Event function EVENT:onEvent( Event ) self:F2( { _EVENTCODES[Event.id], Event } ) @@ -3805,7 +6613,7 @@ function EVENT:onEvent( Event ) Event.WeaponName = Event.Weapon:getTypeName() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end - self:E( { _EVENTCODES[Event.id], Event } ) + self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } ) for ClassName, EventData in pairs( self.Events[Event.id] ) do if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } ) @@ -4190,8 +6998,8 @@ function MENU_COALITION_COMMAND:Remove() end --- This module contains the GROUP class. -- --- 1) @{Group#GROUP} class, extends @{Base#BASE} --- ============================================= +-- 1) @{Group#GROUP} class, extends @{Controllable#CONTROLLABLE} +-- ============================================================= -- The @{Group#GROUP} class is a wrapper class to handle the DCS Group objects: -- -- * Support all DCS Group APIs. @@ -4339,28 +7147,18 @@ end --- The GROUP class -- @type GROUP --- @extends Base#BASE --- @field DCSGroup#Group DCSGroup The DCS group class. +-- @extends Controllable#CONTROLLABLE -- @field #string GroupName The name of the group. GROUP = { ClassName = "GROUP", - GroupName = "", - GroupID = 0, - Controller = nil, - DCSGroup = nil, - WayPointFunctions = {}, } ---- A DCSGroup --- @type DCSGroup --- @field id_ The ID of the group in DCS - --- Create a new GROUP from a DCSGroup -- @param #GROUP self -- @param DCSGroup#Group GroupName The DCS Group name -- @return #GROUP self function GROUP:Register( GroupName ) - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName return self @@ -4395,7 +7193,7 @@ end --- Returns the DCS Group. -- @param #GROUP self -- @return DCSGroup#Group The DCS Group. -function GROUP:GetDCSGroup() +function GROUP:GetDCSObject() local DCSGroup = Group.getByName( self.GroupName ) if DCSGroup then @@ -4413,7 +7211,7 @@ end function GROUP:IsAlive() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupIsAlive = DCSGroup:isExist() @@ -4431,7 +7229,7 @@ end function GROUP:Destroy() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then for Index, UnitData in pairs( DCSGroup:getUnits() ) do @@ -4450,7 +7248,7 @@ end function GROUP:GetCategory() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() self:T3( GroupCategory ) @@ -4466,7 +7264,7 @@ end function GROUP:GetCategoryName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local CategoryNames = { [Group.Category.AIRPLANE] = "Airplane", @@ -4490,7 +7288,7 @@ end function GROUP:GetCoalition() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCoalition = DCSGroup:getCoalition() self:T3( GroupCoalition ) @@ -4507,7 +7305,7 @@ end function GROUP:GetCountry() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCountry = DCSGroup:getUnit(1):getCountry() self:T3( GroupCountry ) @@ -4517,40 +7315,6 @@ function GROUP:GetCountry() return nil end ---- Returns the name of the DCS Group. --- @param #GROUP self --- @return #string The DCS Group name. -function GROUP:GetName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupName = DCSGroup:getName() - self:T3( GroupName ) - return GroupName - end - - return nil -end - ---- Returns the DCS Group identifier. --- @param #GROUP self --- @return #number The identifier of the DCS Group. -function GROUP:GetID() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupID = DCSGroup:getID() - self:T3( GroupID ) - return GroupID - 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 @@ -4559,7 +7323,7 @@ end function GROUP:GetUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) @@ -4579,7 +7343,7 @@ end function GROUP:GetDCSUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) @@ -4596,7 +7360,7 @@ end -- @return #number The DCS Group size. function GROUP:GetSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupSize = DCSGroup:getSize() @@ -4614,7 +7378,7 @@ end -- @return #number The DCS Group initial size. function GROUP:GetInitialSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupInitialSize = DCSGroup:getInitialSize() @@ -4630,7 +7394,7 @@ end -- @return #table The UNITs wrappers. function GROUP:GetUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -4651,7 +7415,7 @@ end -- @return #table The DCS Units. function GROUP:GetDCSUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -4662,117 +7426,13 @@ function GROUP:GetDCSUnits() return nil end ---- Get the controller for the GROUP. --- @param #GROUP self --- @return DCSController#Controller -function GROUP:_GetController() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupController = DCSGroup:getController() - self:T3( GroupController ) - return GroupController - end - - return nil -end - - ---- Retrieve the group mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Group#GROUP:WayPointFunction} to define the hook functions for specific waypoints. --- Use the method @{Group@GROUP:WayPointExecute) to start the execution of the new mission plan. --- Note that when WayPointInitialize is called, the Mission of the group is RESTARTED! --- @param #GROUP self --- @param #table WayPoints If WayPoints is given, then use the route. --- @return #GROUP -function GROUP:WayPointInitialize( WayPoints ) - - if WayPoints then - self.WayPoints = WayPoints - else - self.WayPoints = self:GetTaskRoute() - end - - return self -end - - ---- Registers a waypoint function that will be executed when the group moves over the WayPoint. --- @param #GROUP 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 group moves over the waypoint. The waypoint function takes variable parameters. --- @return #GROUP -function GROUP: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 GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) - self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) - - local DCSTask - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) " - - if FunctionArguments and #FunctionArguments > 0 then - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )" - 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 group will be 1! --- @param #GROUP 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 #GROUP -function GROUP:WayPointExecute( 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 - --- Activates a GROUP. -- @param #GROUP self function GROUP:Activate() self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSGroup() ) - return self:GetDCSGroup() + trigger.action.activateGroup( self:GetDCSObject() ) + return self:GetDCSObject() end @@ -4782,7 +7442,7 @@ end function GROUP:GetTypeName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupTypeName = DCSGroup:getUnit(1):getTypeName() @@ -4799,7 +7459,7 @@ end function GROUP:GetCallsign() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCallSign = DCSGroup:getUnit(1):getCallsign() @@ -4811,11 +7471,14 @@ function GROUP:GetCallsign() end --- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. +-- @param #GROUP self -- @return DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. function GROUP:GetPointVec2() self:F2( self.GroupName ) - local GroupPointVec2 = self:GetUnit(1):GetPointVec2() + local UnitPoint = self:GetUnit(1) + UnitPoint:GetPointVec2() + local GroupPointVec2 = UnitPoint:GetPointVec2() self:T3( GroupPointVec2 ) return GroupPointVec2 end @@ -4893,7 +7556,7 @@ end function GROUP:IsAir() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER @@ -4910,7 +7573,7 @@ end function GROUP:IsHelicopter() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4927,7 +7590,7 @@ end function GROUP:IsAirPlane() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4944,7 +7607,7 @@ end function GROUP:IsGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4961,7 +7624,7 @@ end function GROUP:IsShip() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4979,7 +7642,7 @@ end function GROUP:AllOnGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local AllOnGroundResult = true @@ -5004,7 +7667,7 @@ end function GROUP:GetMaxVelocity() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local MaxVelocity = 0 @@ -5043,1478 +7706,6 @@ function GROUP:GetMaxHeight() end --- Tasks - ---- Popping current Task from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PopCurrentTask() - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:popTask() - return self - end - - return nil -end - ---- Pushing Task on the queue from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PushTask( DCSTask, WaitTime ) - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller:pushTask( DCSTask ) - - if WaitTime then - --routines.scheduleFunction( Controller.pushTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( 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 group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller.setTask( Controller, DCSTask ) - - if not WaitTime then - WaitTime = 1 - end - --routines.scheduleFunction( Controller.setTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) - - return self - end - - return nil -end - - ---- Return a condition section for a controlled task. --- @param #GROUP self --- @param DCSTime#Time time --- @param #string userFlag --- @param #boolean userFlagValue --- @param #string condition --- @param DCSTime#Time duration --- @param #number lastWayPoint --- return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#Task DCSTask --- @param #DCSStopCondition DCSStopCondition --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return #GROUP self -function GROUP:SetCommand( DCSCommand ) - self:F2( DCSCommand ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:setCommand( DCSCommand ) - return self - end - - return nil -end - ---- Perform a switch waypoint command --- @param #GROUP self --- @param #number FromWayPoint --- @param #number ToWayPoint --- @return DCSTask#Task -function GROUP:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) - self:F2( { FromWayPoint, ToWayPoint, Index } ) - - local CommandSwitchWayPoint = { - id = 'SwitchWaypoint', - params = { - fromWaypointIndex = FromWayPoint, - goToWaypointIndex = ToWayPoint, - }, - } - - self:T3( { CommandSwitchWayPoint } ) - return CommandSwitchWayPoint -end - ---- Perform stop route command --- @param #GROUP self --- @param #boolean StopRoute --- @return DCSTask#Task -function GROUP:CommandStopRoute( StopRoute, Index ) - self:F2( { StopRoute, Index } ) - - local CommandStopRoute = { - id = 'StopRoute', - params = { - value = StopRoute, - }, - } - - self:T3( { CommandStopRoute } ) - return CommandStopRoute -end - - --- TASKS FOR AIR GROUPS - - ---- (AIR) Attack a Group. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- AttackGroup = { - -- id = 'AttackGroup', - -- 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 = 'AttackGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- AttackUnit = { - -- id = 'AttackUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- } - -- } - - local DCSTask - DCSTask = { id = 'AttackUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon at the point on the ground. --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- Bombing = { --- id = 'Bombing', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'Bombing', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - 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 #GROUP self --- @param 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 #GROUP self -function GROUP:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.GroupName, 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 group at a specified alititude. --- @param #GROUP self --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #GROUP self -function GROUP:TaskOrbitCircle( Altitude, Speed ) - self:F2( { self.GroupName, Altitude, Speed } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupPoint = self:GetPointVec2() - return self:TaskOrbitCircleAtVec2( GroupPoint, Altitude, Speed ) - end - - return nil -end - - - ---- (AIR) Hold position at the current position of the first unit of the group. --- @param #GROUP self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #GROUP self -function GROUP:TaskHoldPosition() - self:F2( { self.GroupName } ) - - return self:TaskOrbitCircle( 30, 10 ) -end - - - - ---- (AIR) Attacking the map object (building, structure, e.t.c). --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- AttackMapObject = { --- id = 'AttackMapObject', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'AttackMapObject', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon on the runway. --- @param #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- BombingRunway = { --- id = 'BombingRunway', --- params = { --- runwayId = AirdromeId, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'BombingRunway', - params = { - point = Airbase:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Refueling from the nearest tanker. No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskRefueling() - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @param DCSTypes#Vec2 Point The point where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtVec2( Point, Duration ) - self:F2( { self.GroupName, 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 group at a @{Zone#ZONE_RADIUS). --- @param #GROUP self --- @param Zone#ZONE Zone The zone where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtZone( Zone, Duration, RandomPoint ) - self:F2( { self.GroupName, Zone, Duration, RandomPoint } ) - - local Point - if RandomPoint then - Point = Zone:GetRandomVec2() - else - Point = Zone:GetPointVec2() - end - - local DCSTask = self:TaskLandAtVec2( Point, Duration ) - - self:T3( DCSTask ) - return DCSTask -end - - - ---- (AIR) Following another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- If another group is on land the unit / group will orbit around. --- @param #GROUP self --- @param Group#GROUP FollowGroup The group to be followed. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFollow( FollowGroup, PointVec3, LastWaypointIndex ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex } ) - --- Follow = { --- id = 'Follow', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Escort another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- The unit / group will also protect that group from threats of specified types. --- @param #GROUP self --- @param Group#GROUP EscortGroup The group to be escorted. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @param #number EngagementDistanceMax Maximal distance from escorted group to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEscort( FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) - --- Escort = { --- id = 'Escort', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number, --- engagementDistMax = Distance, --- targetTypes = array of AttributeName, --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 The point to fire at. --- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFireAtPoint( PointVec2, Radius ) - self:F2( { self.GroupName, PointVec2, Radius } ) - - -- FireAtPoint = { - -- id = 'FireAtPoint', - -- params = { - -- point = Vec2, - -- radius = Distance, - -- } - -- } - - local DCSTask - DCSTask = { id = 'FireAtPoint', - params = { - point = PointVec2, - radius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Hold ground group from moving. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskHold() - self:F2( { self.GroupName } ) - --- Hold = { --- id = 'Hold', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Hold', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- TASKS FOR AIRBORNE AND GROUND UNITS/GROUPS - ---- (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Designation, Datalink } ) - --- FAC_AttackGroup = { --- id = 'FAC_AttackGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_AttackGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - --- EN-ROUTE TASKS FOR AIRBORNE GROUPS - ---- (AIR) Engaging targets of defined types. --- @param #GROUP self --- @param 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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) - self:F2( { self.GroupName, 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. --- @param DCSTypes#Distance Radius Radius of the zone. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) - self:F2( { self.GroupName, PointVec2, Radius, TargetTypes, Priority } ) - --- EngageTargetsInZone = { --- id = 'EngageTargetsInZone', --- params = { --- point = Vec2, --- zoneRadius = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargetsInZone', - params = { - point = PointVec2, - zoneRadius = Radius, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- EngageGroup = { - -- id = 'EngageGroup ', - -- 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 = 'EngageGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageUnit( AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- EngageUnit = { - -- id = 'EngageUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- priority = number, - -- } - -- } - - local DCSTask - DCSTask = { id = 'EngageUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskAWACS( ) - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskTanker( ) - self:F2( { self.GroupName } ) - --- Tanker = { --- id = 'Tanker', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Tanker', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for ground units/groups - ---- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEWR( ) - self:F2( { self.GroupName } ) - --- EWR = { --- id = 'EWR', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'EWR', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for airborne and ground units/groups - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) - --- FAC_EngageGroup = { --- id = 'FAC_EngageGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean, --- priority = number, --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_EngageGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - priority = Priority, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC( Radius, Priority ) - self:F2( { self.GroupName, 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 group to a Vec2 Point, wait for a defined duration and embark a group. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Duration The duration in seconds to wait. --- @param #GROUP EmbarkingGroup The group to be embarked. --- @return DCSTask#Task The DCS task structure -function GROUP:TaskEmbarking( Point, Duration, EmbarkingGroup ) - self:F2( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) - - local DCSTask - DCSTask = { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - groupsForEmbarking = { EmbarkingGroup.GroupID }, - 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 group when arrived within a defined Radius. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Radius The radius of the embarking zone around the Point. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEmbarkToTransport( Point, Radius ) - self:F2( { self.GroupName, Point, Radius } ) - - local DCSTask --DCSTask#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 #GROUP self --- @param #table TaskMission A table containing the mission task. --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param #table Points A table of route points. --- @return DCSTask#Task -function GROUP:TaskRoute( Points ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR + GROUND) Make the Group move to fly to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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 Group move to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec3() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.z - PointFrom.alt = GroupPoint.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 group to follow a given route. --- @param #GROUP self --- @param #table GoPoints A table of Route Points. --- @return #GROUP self -function GROUP:Route( GoPoints ) - self:F2( GoPoints ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Points = routines.utils.deepCopy( GoPoints ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } - local Controller = self:_GetController() - --Controller.setTask( Controller, MissionTask ) - --routines.scheduleFunction( Controller.setTask, { Controller, MissionTask}, timer.getTime() + 1 ) - SCHEDULER:New( Controller, Controller.setTask, { MissionTask }, 1 ) - return self - end - - return nil -end - - - ---- (AIR + GROUND) Route the group to a given zone. --- The group final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param 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 GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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:GetPointVec2() - 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 Group to an @{Airbase#AIRBASE} --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param Airbase#AIRBASE ReturnAirbase The @{Airbase#AIRBASE} to return to. --- @param #number Speed (optional) The speed. --- @return #string The route -function GROUP: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 DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - local GroupVelocity = self:GetMaxVelocity() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = GroupVelocity - - - local PointTo = {} - local AirbasePoint = ReturnAirbase:GetPointVec2() - - 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 - --- @param Group#GROUP self function GROUP:Respawn( Template ) @@ -6549,26 +7740,6 @@ function GROUP:GetTemplate() end --- Commands - ---- Do Script command --- @param #GROUP self --- @param #string DoScript --- @return #DCSCommand -function GROUP:CommandDoScript( DoScript ) - - local DCSDoScript = { - id = "Script", - params = { - command = DoScript, - }, - } - - self:T3( DCSDoScript ) - return DCSDoScript -end - - --- Return the mission template of the group. -- @param #GROUP self -- @return #table The MissionTemplate @@ -6639,359 +7810,6 @@ function GROUP:CopyRoute( Begin, End, Randomize, Radius ) end -function GROUP:GetDetectedTargets() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - return self:_GetController():getDetectedTargets() - end - - return nil -end - -function GROUP:IsTargetDetected( DCSObject ) - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP hold their weapons? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEHoldFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Holding weapons. --- @param Group#GROUP self --- @return Group#GROUP self -function GROUP:OptionROEHoldFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack returning on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEReturnFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Return fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEReturnFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack designated targets? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEOpenFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Openfire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEOpenFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack targets of opportunity? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEWeaponFreePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Weapon free. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEWeaponFree() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP ignore enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTNoReactionPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- No evasion on enemy threats. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTNoReaction() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade using passive defenses? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTPassiveDefensePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Evasion passive defense. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTPassiveDefense() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTEvadeFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTEvadeFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on fire using vertical manoeuvres? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTVerticalPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire using vertical manoeuvres. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTVertical() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 - -- Message APIs --- Returns a message for a coalition or a client. @@ -7002,7 +7820,7 @@ end function GROUP:Message( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. self:GetTypeName() .. ")" ) end @@ -7018,7 +7836,7 @@ end function GROUP:MessageToAll( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToAll() end @@ -7034,7 +7852,7 @@ end function GROUP:MessageToRed( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToRed() end @@ -7050,7 +7868,7 @@ end function GROUP:MessageToBlue( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToBlue() end @@ -7067,7 +7885,7 @@ end function GROUP:MessageToClient( Message, Duration, Client ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToClient( Client ) end @@ -7076,8 +7894,8 @@ function GROUP:MessageToClient( Message, Duration, Client ) end --- This module contains the UNIT class. -- --- 1) @{Unit#UNIT} class, extends @{Base#BASE} --- =========================================== +-- 1) @{Unit#UNIT} class, extends @{Controllable#CONTROLLABLE} +-- =========================================================== -- The @{Unit#UNIT} class is a wrapper class to handle the DCS Unit objects: -- -- * Support all DCS Unit APIs. @@ -7150,18 +7968,11 @@ end --- The UNIT class -- @type UNIT --- @extends Base#BASE +-- @extends Controllable#CONTROLLABLE -- @field #UNIT.FlareColor FlareColor -- @field #UNIT.SmokeColor SmokeColor UNIT = { ClassName="UNIT", - CategoryName = { - [Unit.Category.AIRPLANE] = "Airplane", - [Unit.Category.HELICOPTER] = "Helicoper", - [Unit.Category.GROUND_UNIT] = "Ground Unit", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - }, FlareColor = { Green = trigger.flareColor.Green, Red = trigger.flareColor.Red, @@ -7196,13 +8007,10 @@ UNIT = { --- Create a new UNIT from DCSUnit. -- @param #UNIT self --- @param DCSUnit#Unit DCSUnit --- @param Database#DATABASE Database +-- @param #string UnitName The name of the DCS unit. -- @return Unit#UNIT function UNIT:Register( UnitName ) - - local self = BASE:Inherit( self, BASE:New() ) - self:F2( UnitName ) + local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) self.UnitName = UnitName return self end @@ -7230,7 +8038,10 @@ function UNIT:FindByName( UnitName ) return UnitFound end -function UNIT:GetDCSUnit() + +--- @param #UNIT self +-- @return DCSUnit#Unit +function UNIT:GetDCSObject() local DCSUnit = Unit.getByName( self.UnitName ) @@ -7241,78 +8052,8 @@ function UNIT:GetDCSUnit() return nil end ---- Returns coalition of the Unit. --- @param Unit#UNIT self --- @return DCSCoalitionObject#coalition.side The side of the coalition. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCoalition() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCoalition = DCSUnit:getCoalition() - self:T3( UnitCoalition ) - return UnitCoalition - end - - return nil -end - ---- Returns country of the Unit. --- @param Unit#UNIT self --- @return DCScountry#country.id The country identifier. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCountry() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCountry = DCSUnit:getCountry() - self:T3( UnitCountry ) - return UnitCountry - end - - return nil -end - - ---- Returns DCS Unit object name. --- The function provides access to non-activated units too. --- @param Unit#UNIT self --- @return #string The name of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitName = self.UnitName - return UnitName - end - - return nil -end ---- Returns if the unit is alive. --- @param Unit#UNIT self --- @return #boolean true if Unit is alive. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAlive() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitIsAlive = DCSUnit:isExist() - return UnitIsAlive - end - - return false -end --- Returns if the unit is activated. -- @param Unit#UNIT self @@ -7321,7 +8062,7 @@ end function UNIT:IsActive() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -7332,30 +8073,25 @@ function UNIT:IsActive() return nil end ---- Returns if the unit is located above a runway. +--- Returns the Unit's callsign - the localized string. -- @param Unit#UNIT self --- @return #boolean true if Unit is above a runway. +-- @return #string The Callsign of the Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAboveRunway() +function UNIT:GetCallSign() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - - local PointVec2 = self:GetPointVec2() - local SurfaceType = land.getSurfaceType( PointVec2 ) - local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - - self:T2( IsAboveRunway ) - return IsAboveRunway + 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#UNIT self -- @return #string Player Name @@ -7363,7 +8099,7 @@ end function UNIT:GetPlayerName() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -7377,23 +8113,6 @@ function UNIT:GetPlayerName() return nil end ---- Returns the unit's unique identifier. --- @param Unit#UNIT self --- @return DCSUnit#Unit.ID Unit ID --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetID() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitID = DCSUnit:getID() - return UnitID - 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. @@ -7404,7 +8123,7 @@ end function UNIT:GetNumber() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitNumber = DCSUnit:getNumber() @@ -7421,7 +8140,7 @@ end function UNIT:GetGroup() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) @@ -7432,69 +8151,23 @@ function UNIT:GetGroup() end ---- Returns the unit's callsign - the localized string. +-- 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#UNIT self --- @return #string The Callsign of the Unit. +-- @return #string The name of the DCS Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCallSign() - self:F2( self.UnitName ) +function UNIT:GetPrefix() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitCallSign = DCSUnit:getCallsign() - return UnitCallSign - end - - return nil -end - ---- Returns the unit's health. Dead units has health <= 1.0. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife = DCSUnit:getLife() - return UnitLife - end - - return nil -end - ---- Returns the Unit's initial health. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife0 = DCSUnit:getLife0() - return UnitLife0 - end - - return 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#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:GetDCSUnit() - - if DCSUnit then - local UnitFuel = DCSUnit:getFuel() - return UnitFuel + local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) + self:T3( UnitPrefix ) + return UnitPrefix end return nil @@ -7507,7 +8180,7 @@ end function UNIT:GetAmmo() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitAmmo = DCSUnit:getAmmo() @@ -7524,7 +8197,7 @@ end function UNIT:GetSensors() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitSensors = DCSUnit:getSensors() @@ -7548,7 +8221,7 @@ end function UNIT:GetRadar() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() @@ -7558,63 +8231,52 @@ function UNIT:GetRadar() return nil, nil end --- Need to add here functions to check if radar is on and which object etc. - ---- Returns unit descriptor. Descriptor type depends on unit category. +--- 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#UNIT self --- @return DCSUnit#Unit.Desc The Unit descriptor. +-- @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:GetDesc() +function UNIT:GetFuel() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitDesc = DCSUnit:getDesc() - self:T2( UnitDesc ) - return UnitDesc + local UnitFuel = DCSUnit:getFuel() + return UnitFuel end - self:E( "Unit " .. self.UnitName .. "not found!" ) return nil end - ---- Returns the type name of the DCS Unit. +--- Returns the unit's health. Dead units has health <= 1.0. -- @param Unit#UNIT self --- @return #string The type name of the DCS Unit. +-- @return #number The Unit's health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetTypeName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() +function UNIT:GetLife() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitTypeName = DCSUnit:getTypeName() - self:T3( UnitTypeName ) - return UnitTypeName + local UnitLife = DCSUnit:getLife() + return UnitLife end - - return nil + + return nil end - - ---- 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. +--- Returns the Unit's initial health. -- @param Unit#UNIT self --- @return #string The name of the DCS Unit. +-- @return #number The Unit's initial health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPrefix() - self:F2( self.UnitName ) +function UNIT:GetLife0() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix + local UnitLife0 = DCSUnit:getLife0() + return UnitLife0 end return nil @@ -7622,83 +8284,6 @@ end ---- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec2 The 2D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec2() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - - local UnitPointVec2 = {} - UnitPointVec2.x = UnitPointVec3.x - UnitPointVec2.y = UnitPointVec3.z - - self:T2( UnitPointVec2 ) - return UnitPointVec2 - end - - return nil -end - - ---- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The 3D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - self:T3( UnitPointVec3 ) - return UnitPointVec3 - end - - return nil -end - ---- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Position The 3D position vectors of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPositionVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPosition = DCSUnit:getPosition() - self:T3( UnitPosition ) - return UnitPosition - end - - return nil -end - ---- Returns the DCS Unit velocity vector. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The velocity vector --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetVelocity() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitVelocityVec3 = DCSUnit:getVelocity() - self:T3( UnitVelocityVec3 ) - return UnitVelocityVec3 - end - - return nil -end -- Is functions @@ -7736,40 +8321,6 @@ function UNIT:IsNotInZone( Zone ) end end ---- Returns true if the DCS Unit is in the air. --- @param Unit#UNIT self --- @return #boolean true if in the air. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:InAir() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitInAir = DCSUnit:inAir() - self:T3( UnitInAir ) - return UnitInAir - end - - return nil -end - ---- Returns the altitude of the DCS Unit. --- @param Unit#UNIT self --- @return DCSTypes#Distance The altitude of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetAltitude() - self:F2() - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPoint() --DCSTypes#Vec3 - return UnitPointVec3.y - end - - return nil -end --- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. -- @param Unit#UNIT self @@ -7780,7 +8331,7 @@ end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitPos = self:GetPointVec3() @@ -7798,41 +8349,6 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) return nil end ---- Returns the DCS Unit category name as defined within the DCS Unit Descriptor. --- @param Unit#UNIT self --- @return #string The DCS Unit Category Name -function UNIT:GetCategoryName() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCategoryName = self.CategoryName[ self:GetDesc().category ] - return UnitCategoryName - end - - return nil -end - ---- Returns the DCS Unit heading. --- @param Unit#UNIT self --- @return #number The DCS Unit heading -function UNIT:GetHeading() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - - local UnitPosition = DCSUnit:getPosition() - if UnitPosition then - local UnitHeading = math.atan2( UnitPosition.x.z, UnitPosition.x.x ) - if UnitHeading < 0 then - UnitHeading = UnitHeading + 2 * math.pi - end - self:T2( UnitHeading ) - return UnitHeading - end - end - - return nil -end --- Signal a flare at the position of the UNIT. @@ -8422,33 +8938,34 @@ 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 DCSTypes#Vec2 PointVec2 The location to test. -- @return #boolean true if the location is within the zone. function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 ) self:F2( PointVec2 ) - local i - local j - local c = false + local Next + local Prev + local InPolygon = false - i = 1 - j = #self.Polygon + Next = 1 + Prev = #self.Polygon - while i < #self.Polygon do - j = i - i = i + 1 - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) - if ( ( ( self.Polygon[i].y > PointVec2.y ) ~= ( self.Polygon[j].y > PointVec2.y ) ) and - ( PointVec2.x < ( self.Polygon[j].x - self.Polygon[i].x ) * ( PointVec2.y - self.Polygon[i].y ) / ( self.Polygon[j].y - self.Polygon[i].y ) + self.Polygon[i].x ) + while Next <= #self.Polygon do + self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) + if ( ( ( self.Polygon[Next].y > PointVec2.y ) ~= ( self.Polygon[Prev].y > PointVec2.y ) ) and + ( PointVec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( PointVec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) ) then - c = not c + InPolygon = not InPolygon end - self:T2( { "c = ", c } ) + self:T2( { InPolygon = InPolygon } ) + Prev = Next + Next = Next + 1 end - self:T( { "c = ", c } ) - return c + self:T( { InPolygon = InPolygon } ) + return InPolygon end --- Define a random @{DCSTypes#Vec2} within the zone. @@ -9007,8 +9524,8 @@ function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInter end --- This module contains the STATIC class. -- --- 1) @{Static#STATIC} class, extends @{Unit#UNIT} --- =============================================== +-- 1) @{Static#STATIC} class, extends @{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 @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: @@ -9045,7 +9562,7 @@ end --- The STATIC class -- @type STATIC --- @extends Unit#UNIT +-- @extends Positionable#POSITIONABLE STATIC = { ClassName = "STATIC", } @@ -9069,10 +9586,7 @@ function STATIC:FindByName( StaticName ) end function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, UNIT:Register( StaticName ) ) - - self:F( StaticName ) - + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) return self end @@ -9090,8 +9604,8 @@ end -- -- === -- --- 1) @{Airbase#AIRBASE} class, extends @{Base#BASE} --- ================================================= +-- 1) @{Airbase#AIRBASE} class, extends @{Positionable#POSITIONABLE} +-- ================================================================= -- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: -- -- * Support all DCS Airbase APIs. @@ -9137,7 +9651,7 @@ end --- The AIRBASE class -- @type AIRBASE --- @extends Base#BASE +-- @extends Positionable#POSITIONABLE AIRBASE = { ClassName="AIRBASE", CategoryName = { @@ -9151,13 +9665,11 @@ AIRBASE = { --- Create a new AIRBASE from DCSAirbase. -- @param #AIRBASE self --- @param DCSAirbase#Airbase DCSAirbase --- @param Database#DATABASE Database +-- @param #string AirbaseName The name of the airbase. -- @return Airbase#AIRBASE function AIRBASE:Register( AirbaseName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( AirbaseName ) + local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) self.AirbaseName = AirbaseName return self end @@ -9515,6 +10027,8 @@ end function DATABASE:AddUnit( DCSUnitName ) if not self.UNITS[DCSUnitName] then + local UnitRegister = UNIT:Register( DCSUnitName ) + self:E( UnitRegister.UnitName ) self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) end @@ -9635,7 +10149,7 @@ function DATABASE:AddPlayer( UnitName, PlayerName ) if PlayerName then self:E( { "Add player for unit:", UnitName, PlayerName } ) - self.PLAYERS[PlayerName] = UNIT:FindByName( UnitName ) + self.PLAYERS[PlayerName] = self:FindUnit( UnitName ) self.PLAYERSJOINED[PlayerName] = PlayerName end end @@ -10413,6 +10927,15 @@ function SET_BASE:_Find( ObjectName ) end +--- Gets the Set. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:GetSet() + self:F2() + + return self.Set +end + --- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. -- @param #SET_BASE self -- @param #string ObjectName @@ -10543,7 +11066,7 @@ end -- @param #SET_BASE self -- @param Event#EVENTDATA Event function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F2( { Event } ) + self:F3( { Event } ) if Event.IniDCSUnit then local ObjectName, Object = self:FindInDatabase( Event ) @@ -10599,7 +11122,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen local function CoRoutine() local Count = 0 for ObjectID, Object in pairs( Set ) do - self:T2( Object ) + self:T3( Object ) if Function then if Function( unpack( FunctionArguments ), Object ) == true then IteratorFunction( Object, unpack( arg ) ) @@ -10688,7 +11211,7 @@ function SET_BASE:IsIncludeObject( Object ) return true end ---- Flushes the current SET_BASE contents in the log ... (for debug reasons). +--- 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() @@ -11309,7 +11832,6 @@ end function SET_UNIT:FindInDatabase( Event ) self:F3( { Event } ) - self:E( { Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] } ) return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end @@ -12350,6 +12872,10 @@ end Include.File( "Routines" ) Include.File( "Base" ) +Include.File( "Object" ) +Include.File( "Identifiable" ) +Include.File( "Positionable" ) +Include.File( "Controllable" ) Include.File( "Scheduler" ) Include.File( "Event" ) Include.File( "Menu" ) @@ -12388,6 +12914,7 @@ Include.File( "PatrolZone" ) Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) +Include.File( "FAC" ) -- The order of the declarations is important here. Don't touch it. @@ -14087,7 +14614,6 @@ function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) end self:T( "Routing " .. CargoHostName ) - --routines.scheduleFunction( routines.goRoute, { CargoHostName, Points}, timer.getTime() + 4 ) SCHEDULER:New( self, routines.goRoute, { CargoHostName, Points }, 4 ) return Valid @@ -17323,7 +17849,6 @@ function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, _EVENTDISPATCHER:OnBirth( self._OnEventBirth, self ) - --self.CleanUpScheduler = routines.scheduleFunction( self._CleanUpScheduler, { self }, timer.getTime() + 1, TimeInterval ) self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) return self @@ -17448,7 +17973,6 @@ function CLEANUP:_EventShot( Event ) if ( CurrentLandingZoneID ) then -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. --_SEADmissile:destroy() - --routines.scheduleFunction( CLEANUP._DestroyMissile, { self, Event.Weapon }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) end end @@ -17465,7 +17989,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.IniDCSUnit }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) end end @@ -17476,7 +17999,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.TgtDCSUnit }, timer.getTime() + 0.1 ) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) end end @@ -19038,7 +19560,6 @@ function SEAD:EventShot( Event ) local SEADUnitName = Event.IniDCSUnitName local SEADWeapon = Event.Weapon -- Identify the weapon fired local SEADWeaponName = Event.WeaponName -- return weapon type - --trigger.action.outText( string.format("Alerte, depart missile " ..string.format(SEADWeaponName)), 20) --debug message -- 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 @@ -19064,10 +19585,10 @@ function SEAD:EventShot( Event ) local Skills = { "Average", "Good", "High", "Excellent" } _targetskill = Skills[ math.random(1,4) ] end - self:T( _targetskill ) -- debug message for skill check + 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)) ) --debug message + 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)) @@ -19675,7 +20196,6 @@ function ESCORT:MenuReportTargets( Seconds ) self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, Seconds ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) return self @@ -19897,7 +20417,6 @@ function ESCORT._SwitchReportNearbyTargets( MenuParam ) if self.ReportTargets then if not self.ReportTargetsScheduler then - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, 30 ) end else @@ -19974,16 +20493,6 @@ function ESCORT._AttackTarget( MenuParam ) EscortGroup:OptionROEOpenFire() EscortGroup:OptionROTPassiveDefense() EscortGroup:SetState( EscortGroup, "Escort", self ) --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskAttackUnit( AttackUnit ), --- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -19994,15 +20503,6 @@ function ESCORT._AttackTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -20033,16 +20533,6 @@ function ESCORT._AssistTarget( MenuParam ) if EscortGroupAttack:IsAir() then EscortGroupAttack:OptionROEOpenFire() EscortGroupAttack:OptionROTVertical() --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskAttackUnit( AttackUnit ), --- EscortGroupAttack:TaskOrbitCircle( 500, 350 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -20053,15 +20543,6 @@ function ESCORT._AssistTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -20121,7 +20602,6 @@ function ESCORT._ResumeMission( MenuParam ) table.remove( WayPoints, 1 ) end - --routines.scheduleFunction( EscortGroup.SetTask, {EscortGroup, EscortGroup:TaskRoute( WayPoints ) }, timer.getTime() + 1 ) SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) @@ -22564,9 +23044,64 @@ end -- === -- -- 1) @{Detection#DETECTION_BASE} class, extends @{Base#BASE} --- ===================================================== +-- ========================================================== -- The @{Detection#DETECTION_BASE} class defines the core functions to administer detected objects. --- Detected objects are grouped in SETS of UNITS. +-- +-- 1.1) DETECTION_BASE constructor +-- ------------------------------- +-- Construct a new DETECTION_BASE instance using the @{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: +-- +-- * @{Detection#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. +-- * @{Detection#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. +-- * @{Detection#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. +-- * @{Detection#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. +-- * @{Detection#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. +-- * @{Detection#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. +-- +-- 1.3) Obtain objects detected by DETECTION_BASE +-- ---------------------------------------------- +-- DETECTION_BASE builds @{Set}s of objects detected. These @{Set#SET_BASE}s can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSets}(). +-- The method will return a list (table) of @{Set#SET_BASE} objects. +-- +-- === +-- +-- 2) @{Detection#DETECTION_UNITGROUPS} class, extends @{Detection#DETECTION_BASE} +-- =============================================================================== +-- The @{Detection#DETECTION_UNITGROUPS} class will detect units within the battle zone for a FAC group, +-- and will build a list (table) of @{Set#SET_UNIT}s containing the @{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 @{Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Detection#DETECTION_UNITGROUPS}. +-- +-- Retrieve the DetectedUnitSets with the method @{Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Set#SET_UNIT}s. +-- To understand the amount of sets created, use the method @{Detection#DETECTION_BASE.GetDetectedSetCount}(). +-- If you want to obtain a specific set from the DetectedSets, use the method @{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 @{Detection#DETECTION_BASE.GetDetectionZones}(). +-- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). +-- If you want to obtain a specific zone from the DetectedZones, use the method @{Detection#DETECTION_BASE.GetDetectionZone}() with a given index. +-- +-- 1.4) Flare or Smoke detected units +-- ---------------------------------- +-- Use the methods @{Detection#DETECTION_UNITGROUPS.FlareDetectedUnits}() or @{Detection#DETECTION_UNITGROUPS.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 @{Detection#DETECTION_UNITGROUPS.FlareDetectedZones}() or @{Detection#DETECTION_UNITGROUPS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place. +-- +-- === -- -- @module Detection -- @author Mechanic : Concept & Testing @@ -22578,148 +23113,640 @@ end -- @type DETECTION_BASE -- @field Group#GROUP FACGroup The GROUP in the Forward Air Controller role. -- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @field #DETECTION_BASE.DetectedUnitSets DetectedUnitSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectedZoneRange. --- @field #DETECTION_BASE.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. --- @extends Set#SET_BASE +-- @field #DETECTION_BASE.DetectedSets DetectedSets A list of @{Set#SET_BASE}s containing the objects in each set that were detected. The base class will not build the detected sets, but will leave that to the derived classes. +-- @extends Base#BASE DETECTION_BASE = { ClassName = "DETECTION_BASE", - DetectedUnitSets = {}, - DetectedUnits = {}, + DetectedSets = {}, + DetectedObjects = {}, FACGroup = nil, DetectionRange = nil, - DetectionZoneRange = nil, } ---- @type DETECTION_BASE.DetectedUnitSets --- @list +--- @type DETECTION_BASE.DetectedSets +-- @list --- @type DETECTION_BASE.DetectedZones --- @list +-- @list --- DETECTION constructor. -- @param #DETECTION_BASE self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. -- @return #DETECTION_BASE self -function DETECTION_BASE:New( FACGroup, DetectionRange, DetectionZoneRange ) +function DETECTION_BASE:New( FACGroup, DetectionRange ) -- Inherits from BASE local self = BASE:Inherit( self, BASE:New() ) self.FACGroup = FACGroup self.DetectionRange = DetectionRange - self.DetectionZoneRange = DetectionZoneRange - self.DetectionScheduler = SCHEDULER:New(self, self._DetectionScheduler, { self, "Detection" }, 10, 30, 0.2 ) + self:InitDetectVisual( false ) + self:InitDetectOptical( false ) + self:InitDetectRadar( false ) + self:InitDetectRWR( false ) + self:InitDetectIRST( false ) + self:InitDetectDLINK( false ) + + return self end ---- Form @{Set}s of detected @{Unit#UNIT}s in an array of @{Set#SET_UNIT}s. +--- 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 + +--- Gets the FAC group. +-- @param #DETECTION_BASE self +-- @return Group#GROUP self +function DETECTION_BASE:GetFACGroup() + self:F2() + + return self.FACGroup +end + +--- Get the detected @{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 Set#SET_BASE +function DETECTION_BASE:GetDetectedSet( Index ) + + local DetectionSet = self.DetectedSets[Index] + if DetectionSet then + return DetectionSet + end + + return nil +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 @{Unit#UNIT}s in an array of @{Set#SET_BASE}s. -- @param #DETECTION_BASE self function DETECTION_BASE:_DetectionScheduler( SchedulerName ) self:F2( { SchedulerName } ) - self.DetectedUnitSets = {} + self.DetectedObjects = {} + self.DetectedSets = {} + self.DetectedZones = {} if self.FACGroup:IsAlive() then local FACGroupName = self.FACGroup:GetName() - local FACDetectedTargets = self.FACGroup:GetDetectedTargets() + + local FACDetectedTargets = self.FACGroup:GetDetectedTargets( + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) for FACDetectedTargetID, FACDetectedTarget in pairs( FACDetectedTargets ) do - local FACObject = FACDetectedTarget.object + local FACObject = FACDetectedTarget.object -- DCSObject#Object self:T2( FACObject ) if FACObject and FACObject:isExist() and FACObject.id_ < 50000000 then - local FACDetectedUnit = UNIT:Find( FACObject ) - local FACDetectedUnitName = FACDetectedUnit:GetName() + local FACDetectedObjectName = FACObject:getName() - local FACDetectedUnitPositionVec3 = FACDetectedUnit:GetPointVec3() + local FACDetectedObjectPositionVec3 = FACObject:getPoint() local FACGroupPositionVec3 = self.FACGroup:GetPointVec3() - local Distance = ( ( FACDetectedUnitPositionVec3.x - FACGroupPositionVec3.x )^2 + - ( FACDetectedUnitPositionVec3.y - FACGroupPositionVec3.y )^2 + - ( FACDetectedUnitPositionVec3.z - FACGroupPositionVec3.z )^2 + + local Distance = ( ( FACDetectedObjectPositionVec3.x - FACGroupPositionVec3.x )^2 + + ( FACDetectedObjectPositionVec3.y - FACGroupPositionVec3.y )^2 + + ( FACDetectedObjectPositionVec3.z - FACGroupPositionVec3.z )^2 ) ^ 0.5 / 1000 - self:T( { FACGroupName, FACDetectedUnitName, Distance } ) + self:T( { FACGroupName, FACDetectedObjectName, Distance } ) if Distance <= self.DetectionRange then - if not self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = {} + if not self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = {} end - self.DetectedUnits[FACDetectedUnitName].DetectedUnit = UNIT:FindByName( FACDetectedUnitName ) - self.DetectedUnits[FACDetectedUnitName].Visible = FACDetectedTarget.visible - self.DetectedUnits[FACDetectedUnitName].Type = FACDetectedTarget.type - self.DetectedUnits[FACDetectedUnitName].Distance = FACDetectedTarget.distance + self.DetectedObjects[FACDetectedObjectName].Name = FACDetectedObjectName + self.DetectedObjects[FACDetectedObjectName].Visible = FACDetectedTarget.visible + self.DetectedObjects[FACDetectedObjectName].Type = FACDetectedTarget.type + self.DetectedObjects[FACDetectedObjectName].Distance = FACDetectedTarget.distance else -- if beyond the DetectionRange then nullify... - if self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = nil + if self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = nil end end end end + + self:T2( self.DetectedObjects ) - -- okay, now we have a list of detected unit names ... + -- okay, now we have a list of detected object names ... -- Sort the table based on distance ... - self:T( { "Sorting DetectedUnits table:", self.DetectedUnits } ) - table.sort( self.DetectedUnits, function( a, b ) return a.Distance < b.Distance end ) - self:T( { "Sorted Targets Table:", self.DetectedUnits } ) + self:T( { "Sorting DetectedObjects table:", self.DetectedObjects } ) + table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end ) + self:T( { "Sorted Targets Table:", self.DetectedObjects } ) - -- Now group the DetectedUnits table into SET_UNITs, evaluating the DetectionZoneRange. + -- Now group the DetectedObjects table into SET_BASEs, evaluating the DetectionZoneRange. - if self.DetectedUnits then - for DetectedUnitName, DetectedUnitData in pairs( self.DetectedUnits ) do - local DetectedUnit = DetectedUnitData.DetectedUnit -- Unit#UNIT - if DetectedUnit and DetectedUnit:IsAlive() then - self:T( DetectedUnit:GetName() ) - if #self.DetectedUnitSets == 0 then - self:T( { "Adding Unit Set #", 1 } ) - self.DetectedUnitSets[1] = {} - self.DetectedUnitSets[1].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[1].Set = SET_UNIT:New() - self.DetectedUnitSets[1].Set:AddUnit( DetectedUnit ) - else - local AddedToSet = false - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - self:T( "Detected Unit Set #" .. DetectedUnitSetID ) - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - if DetectedUnit:IsInZone( DetectedZone ) then - self:T( "Adding to Unit Set #" .. DetectedUnitSetID ) - self.DetectedUnitSets[DetectedUnitSetID].Set:AddUnit( DetectedUnit ) - AddedToSet = true - end - end - if AddedToSet == false then - self:T( "Adding new Unit Set #" .. #self.DetectedUnitSets+1 ) - self.DetectedUnitSets[#self.DetectedUnitSets+1] = {} - self.DetectedUnitSets[#self.DetectedUnitSets].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[#self.DetectedUnitSets].Set = SET_UNIT:New() - self.DetectedUnitSets[#self.DetectedUnitSets].Set:AddUnit( DetectedUnit ) - end - end - end - end + if self.DetectedObjects then + self:CreateDetectionSets() end - -- Now all the tests should have been build, now make some smoke and flares... - - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - self:T( "Detected Set #" .. DetectedUnitSetID ) - DetectedUnitSet:ForEachUnit( - --- @param Unit#UNIT DetectedUnit - function( DetectedUnit ) - self:T( DetectedUnit:GetName() ) + + end +end + +--- @type DETECTION_UNITGROUPS.DetectedSets +-- @list +-- + + +--- @type DETECTION_UNITGROUPS.DetectedZones +-- @list +-- + + +--- DETECTION_UNITGROUPS class +-- @type DETECTION_UNITGROUPS +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @field #DETECTION_UNITGROUPS.DetectedSets DetectedSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectionZoneRange. +-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. +-- @extends Detection#DETECTION_BASE +DETECTION_UNITGROUPS = { + ClassName = "DETECTION_UNITGROUPS", + DetectedZones = {}, +} + + + +--- DETECTION_UNITGROUPS constructor. +-- @param Detection#DETECTION_UNITGROUPS self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @return Detection#DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:New( FACGroup, DetectionRange, DetectionZoneRange ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( FACGroup, DetectionRange ) ) + self.DetectionZoneRange = DetectionZoneRange + + self:Schedule( 10, 30 ) + + return self +end + +--- Get the detected @{Zone#ZONE_UNIT}s. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones +function DETECTION_UNITGROUPS:GetDetectedZones() + + local DetectedZones = self.DetectedZones + return DetectedZones +end + +--- Get the amount of @{Zone#ZONE_UNIT}s with detected units. +-- @param #DETECTION_UNITGROUPS self +-- @return #number Count +function DETECTION_UNITGROUPS:GetDetectedZoneCount() + + local DetectedZoneCount = #self.DetectedZones + return DetectedZoneCount +end + +--- Get a SET of detected objects using a given numeric index. +-- @param #DETECTION_UNITGROUPS self +-- @param #number Index +-- @return Zone#ZONE_UNIT +function DETECTION_UNITGROUPS:GetDetectedZone( Index ) + + local DetectedZone = self.DetectedZones[Index] + if DetectedZone then + return DetectedZone + end + + return nil +end + +--- Smoke the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedUnits() + self:F2() + + self._SmokeDetectedUnits = true + return self +end + +--- Flare the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedUnits() + self:F2() + + self._FlareDetectedUnits = true + return self +end + +--- Smoke the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedZones() + self:F2() + + self._SmokeDetectedZones = true + return self +end + +--- Flare the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedZones() + self:F2() + + self._FlareDetectedZones = true + return self +end + + +--- Make a DetectionSet table. This function will be overridden in the derived clsses. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:CreateDetectionSets() + self:F2() + + for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do + self:T( DetectedUnitData.Name ) + local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT + if DetectedUnit and DetectedUnit:IsAlive() then + self:T( DetectedUnit:GetName() ) + if #self.DetectedSets == 0 then + self:T( { "Adding Unit Set #", 1 } ) + self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[1] = SET_UNIT:New() + self.DetectedSets[1]:AddUnit( DetectedUnit ) + else + local AddedToSet = false + for DetectedZoneIndex = 1, #self.DetectedZones do + self:T( "Detected Unit Set #" .. DetectedZoneIndex ) + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + if DetectedUnit:IsInZone( DetectedZone ) then + self:T( "Adding to Unit Set #" .. DetectedZoneIndex ) + DetectedUnitSet:AddUnit( DetectedUnit ) + AddedToSet = true + end + end + if AddedToSet == false then + local DetectedZoneIndex = #self.DetectedZones + 1 + self:T( "Adding new zone #" .. DetectedZoneIndex ) + self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New() + self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit ) + end + end + end + end + + -- Now all the tests should have been build, now make some smoke and flares... + + for DetectedZoneIndex = 1, #self.DetectedZones do + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + self:T( "Detected Set #" .. DetectedZoneIndex ) + DetectedUnitSet:ForEachUnit( + --- @param Unit#UNIT DetectedUnit + function( DetectedUnit ) + self:T( DetectedUnit:GetName() ) + if self._FlareDetectedUnits then DetectedUnit:FlareRed() end - ) + if self._SmokeDetectedUnits then + DetectedUnit:SmokeRed() + end + end + ) + if self._FlareDetectedZones then + DetectedZone:FlareZone( POINT_VEC3.SmokeColor.White, 30, math.random( 0,90 ) ) + end + if self._SmokeDetectedZones then DetectedZone:SmokeZone( POINT_VEC3.SmokeColor.White, 30 ) end end + end + + +--- This module contains the FAC classes. +-- +-- === +-- +-- 1) @{Fac#FAC_BASE} class, extends @{Base#BASE} +-- ============================================== +-- The @{Fac#FAC_BASE} class defines the core functions to report detected objects to clients. +-- Reportings can be done in several manners, and it is up to the derived classes if FAC_BASE to model the reporting behaviour. +-- +-- 1.1) FAC_BASE constructor: +-- ---------------------------- +-- * @{Fac#FAC_BASE.New}(): Create a new FAC_BASE instance. +-- +-- 1.2) FAC_BASE reporting: +-- ------------------------ +-- Derived FAC_BASE classes will reports detected units using the method @{Fac#FAC_BASE.ReportDetected}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the reporting can be changed using the methods @{Fac#FAC_BASE.SetReportInterval}(). +-- To control how long a reporting message is displayed, use @{Fac#FAC_BASE.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Fac#FAC_BASE.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Reporting can be started and stopped using the methods @{Fac#FAC_BASE.StartReporting}() and @{Fac#FAC_BASE.StopReporting}() respectively. +-- If an ad-hoc report is requested, use the method @{Fac#FAC_BASE#ReportNow}(). +-- +-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. +-- +-- === +-- +-- 2) @{Fac#FAC_REPORTING} class, extends @{Fac#FAC_BASE} +-- ====================================================== +-- The @{Fac#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Fac#FAC_BASE} class. +-- +-- 2.1) FAC_REPORTING constructor: +-- ------------------------------- +-- The @{Fac#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance. +-- +-- === +-- +-- @module Fac +-- @author Mechanic, Prof_Hilactic, FlightControl : Concept & Testing +-- @author FlightControl : Design & Programming + + + +--- FAC_BASE class. +-- @type FAC_BASE +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends Base#BASE +FAC_BASE = { + ClassName = "FAC_BASE", + ClientSet = nil, + Detection = nil, +} + +--- FAC constructor. +-- @param #FAC_BASE self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_BASE self +function FAC_BASE:New( ClientSet, Detection ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) -- Fac#FAC_BASE + + self.ClientSet = ClientSet + self.Detection = Detection + + self:SetReportInterval( 60 ) + self:SetReportDisplayTime( 15 ) + + return self +end + +--- Set the reporting time interval. +-- @param #FAC_BASE self +-- @param #number ReportInterval The interval in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportInterval( ReportInterval ) + self:F2() + + self._ReportInterval = ReportInterval +end + + +--- Set the reporting message display time. +-- @param #FAC_BASE self +-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportDisplayTime( ReportDisplayTime ) + self:F2() + + self._ReportDisplayTime = ReportDisplayTime +end + +--- Get the reporting message display time. +-- @param #FAC_BASE self +-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. +function FAC_BASE:GetReportDisplayTime() + self:F2() + + return self._ReportDisplayTime +end + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_BASE self +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #FAC_BASE self +function FAC_BASE:ReportDetected( DetectedSets ) + self:F2() + + + +end + +--- Schedule the FAC reporting. +-- @param #FAC_BASE 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 #FAC_BASE self +function FAC_BASE:Schedule( DelayTime, ReportInterval ) + self:F2() + + self._ScheduleDelayTime = DelayTime + + self:SetReportInterval( ReportInterval ) + + self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "Fac" }, self._ScheduleDelayTime, self._ReportInterval ) + return self +end + +--- Report the detected @{Unit#UNIT}s detected within the @{DetectION#DETECTION_BASE} object to the @{Set#SET_CLIENT}s. +-- @param #FAC_BASE self +function FAC_BASE:_FacScheduler( SchedulerName ) + self:F2( { SchedulerName } ) + + self.ClientSet:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + if Client:IsAlive() then + local DetectedSets = self.Detection:GetDetectedSets() + return self:ReportDetected( Client, DetectedSets ) + end + end + ) + + return true +end + +-- FAC_REPORTING + +--- FAC_REPORTING class. +-- @type FAC_REPORTING +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends #FAC_BASE +FAC_REPORTING = { + ClassName = "FAC_REPORTING", +} + + +--- FAC_REPORTING constructor. +-- @param #FAC_REPORTING self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_REPORTING self +function FAC_REPORTING:New( ClientSet, Detection ) + + -- Inherits from FAC_BASE + local self = BASE:Inherit( self, FAC_BASE:New( ClientSet, Detection ) ) -- #FAC_REPORTING + + self:Schedule( 5, 60 ) + return self +end + + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_REPORTING self +-- @param Client#CLIENT Client The @{Client} object to where the report needs to go. +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. +function FAC_REPORTING:ReportDetected( Client, DetectedSets ) + self:F2( Client ) + + local DetectedMsg = {} + for DetectedUnitSetID, DetectedUnitSet in pairs( DetectedSets ) do + local UnitSet = DetectedUnitSet -- Set#SET_UNIT + local MT = {} -- Message Text + local UnitTypes = {} + for DetectedUnitID, DetectedUnitData in pairs( UnitSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Unit#UNIT + local UnitType = DetectedUnit:GetTypeName() + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + local MessageText = table.concat( MT, ", " ) + DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedUnitSetID .. ": " .. MessageText + end + local FACGroup = self.Detection:GetFACGroup() + FACGroup:MessageToClient( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Client ) + + return true +end + + BASE:TraceOnOff( false ) env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 96327a527..7f30d885d 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20160622_1015' ) +env.info( 'Moose Generation Timestamp: 20160626_0740' ) local base = _G Include = {} @@ -450,22 +450,6 @@ routines.getNorthCorrection = function(point) --gets the correction needed for end --- the main area -do - -- THE MAIN FUNCTION -- Accessed 100 times/sec. - routines.main = function() - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) --reschedule first in case of Lua error - ---------------------------------------------------------------------------------------------------------- - --area to add new stuff in - - routines.do_scheduled_functions() - end -- end of routines.main - - timer.scheduleFunction(routines.main, {}, timer.getTime() + 2) - -end - - do local idNum = 0 @@ -2969,7 +2953,7 @@ end -- @param Arguments A #table or any field. function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -2998,7 +2982,7 @@ end -- @param Arguments A #table or any field. function BASE:F( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3014,7 +2998,7 @@ end -- @param Arguments A #table or any field. function BASE:F2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3029,7 +3013,7 @@ end -- @param Arguments A #table or any field. function BASE:F3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3044,7 +3028,7 @@ end -- @param Arguments A #table or any field. function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam ) - if ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then + 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" ) @@ -3073,7 +3057,7 @@ end -- @param Arguments A #table or any field. function BASE:T( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3089,7 +3073,7 @@ end -- @param Arguments A #table or any field. function BASE:T2( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3104,7 +3088,7 @@ end -- @param Arguments A #table or any field. function BASE:T3( Arguments ) - if _TraceOnOff then + if debug and _TraceOnOff then local DebugInfoCurrent = debug.getinfo( 2, "nl" ) local DebugInfoFrom = debug.getinfo( 3, "l" ) @@ -3119,25 +3103,2846 @@ end -- @param Arguments A #table or any field. function BASE:E( Arguments ) - 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 ) ) ) + 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 OBJECT class. +-- +-- 1) @{Object#OBJECT} class, extends @{Base#BASE} +-- =========================================================== +-- The @{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: +-- +-- * @{Object#OBJECT.New}(): Create a OBJECT instance. +-- +-- 1.2) OBJECT methods: +-- -------------------------- +-- The following methods can be used to identify an Object object: +-- +-- * @{Object#OBJECT.GetID}(): Returns the ID of the Object object. +-- +-- === +-- +-- @module Object +-- @author FlightControl + +--- The OBJECT class +-- @type OBJECT +-- @extends 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 DCSObject#Object ObjectName The Object name +-- @return #OBJECT self +function OBJECT:New( ObjectName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( ObjectName ) + self.ObjectName = ObjectName + return self +end + + +--- Returns if the Object is alive. +-- @param Object#OBJECT self +-- @return #boolean true if Object is alive. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:IsAlive() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectIsAlive = DCSObject:isExist() + return ObjectIsAlive + end + + return false +end + + + + +--- Returns DCS Object object name. +-- The function provides access to non-activated objects too. +-- @param Object#OBJECT self +-- @return #string The name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectName = self.ObjectName + return ObjectName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the type name of the DCS Object. +-- @param Object#OBJECT self +-- @return #string The type name of the DCS Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetTypeName() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectTypeName = DCSObject:getTypeName() + self:T3( ObjectTypeName ) + return ObjectTypeName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns the Object's callsign - the localized string. +-- @param Object#OBJECT self +-- @return #string The Callsign of the Object. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCallSign() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCallSign = DCSObject:getCallsign() + return ObjectCallSign + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + +--- Returns the DCS Object category name as defined within the DCS Object Descriptor. +-- @param Object#OBJECT self +-- @return #string The DCS Object Category Name +function OBJECT:GetCategoryName() + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCategoryName = _CategoryName[ self:GetDesc().category ] + return ObjectCategoryName + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns coalition of the Object. +-- @param Object#OBJECT self +-- @return DCSCoalitionObject#coalition.side The side of the coalition. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCoalition() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCoalition = DCSObject:getCoalition() + self:T3( ObjectCoalition ) + return ObjectCoalition + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + +--- Returns country of the Object. +-- @param Object#OBJECT self +-- @return DCScountry#country.id The country identifier. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetCountry() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectCountry = DCSObject:getCountry() + self:T3( ObjectCountry ) + return ObjectCountry + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + +--- Returns Object descriptor. Descriptor type depends on Object category. +-- @param Object#OBJECT self +-- @return DCSObject#Object.Desc The Object descriptor. +-- @return #nil The DCS Object is not existing or alive. +function OBJECT:GetDesc() + self:F2( self.ObjectName ) + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local ObjectDesc = DCSObject:getDesc() + self:T2( ObjectDesc ) + return ObjectDesc + end + + self:E( self.ClassName .. " " .. self.ObjectName .. " not found!" ) + return nil +end + + + + + + + + + +--- This module contains the IDENTIFIABLE class. +-- +-- 1) @{Identifiable#IDENTIFIABLE} class, extends @{Object#OBJECT} +-- =============================================================== +-- The @{Identifiable#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#IDENTIFIABLE.New}(): Create a IDENTIFIABLE instance. +-- +-- 1.2) IDENTIFIABLE methods: +-- -------------------------- +-- The following methods can be used to identify an identifiable object: +-- +-- * @{Identifiable#IDENTIFIABLE.GetName}(): Returns the name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.IsAlive}(): Returns if the Identifiable is alive. +-- * @{Identifiable#IDENTIFIABLE.GetTypeName}(): Returns the type name of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCoalition}(): Returns the coalition of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetCountry}(): Returns the country of the Identifiable. +-- * @{Identifiable#IDENTIFIABLE.GetDesc}(): Returns the descriptor structure of the Identifiable. +-- +-- +-- === +-- +-- @module Identifiable +-- @author FlightControl + +--- The IDENTIFIABLE class +-- @type IDENTIFIABLE +-- @extends 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 DCSIdentifiable#Identifiable IdentifiableName The DCS Identifiable name +-- @return #IDENTIFIABLE self +function IDENTIFIABLE:New( IdentifiableName ) + local self = BASE:Inherit( self, BASE:New() ) + self:F2( IdentifiableName ) + self.IdentifiableName = IdentifiableName + return self +end + +--- Returns if the Identifiable is alive. +-- @param Identifiable#IDENTIFIABLE self +-- @return #boolean true if Identifiable is alive. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:IsAlive() + self:F2( 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#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#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 the DCS Identifiable category name as defined within the DCS Identifiable Descriptor. +-- @param Identifiable#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#IDENTIFIABLE self +-- @return DCSCoalitionObject#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#IDENTIFIABLE self +-- @return 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#IDENTIFIABLE self +-- @return DCSIdentifiable#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 + + + + + + + + + +--- This module contains the POSITIONABLE class. +-- +-- 1) @{Positionable#POSITIONABLE} class, extends @{Identifiable#IDENTIFIABLE} +-- =========================================================== +-- The @{Positionable#POSITIONABLE} class is a wrapper class to handle the DCS Positionable objects: +-- +-- * Support all DCS Positionable APIs. +-- * Enhance with Positionable specific APIs not in the DCS Positionable API set. +-- * Manage the "state" of the DCS Positionable. +-- +-- 1.1) POSITIONABLE constructor: +-- ------------------------------ +-- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: +-- +-- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- 1.2) POSITIONABLE methods: +-- -------------------------- +-- The following methods can be used to identify an measurable object: +-- +-- * @{Positionable#POSITIONABLE.GetID}(): Returns the ID of the measurable object. +-- * @{Positionable#POSITIONABLE.GetName}(): Returns the name of the measurable object. +-- +-- === +-- +-- @module Positionable +-- @author FlightControl + +--- The POSITIONABLE class +-- @type POSITIONABLE +-- @extends 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 DCSPositionable#Positionable PositionableName The DCS Positionable name +-- @return #POSITIONABLE self +function POSITIONABLE:New( PositionableName ) + local self = BASE:Inherit( self, IDENTIFIABLE:New( PositionableName ) ) + + return self +end + +--- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Position The 3D position vectors of the DCS Positionable. +-- @return #nil The DCS 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 @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec2 The 2D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec2() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + + local PositionablePointVec2 = {} + PositionablePointVec2.x = PositionablePointVec3.x + PositionablePointVec2.y = PositionablePointVec3.z + + self:T2( PositionablePointVec2 ) + return PositionablePointVec2 + end + + return nil +end + + +--- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Positionable within the mission. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The 3D point vector of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetPointVec3() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPosition().p + self:T3( PositionablePointVec3 ) + return PositionablePointVec3 + end + + return nil +end + +--- Returns the altitude of the DCS Positionable. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Distance The altitude of the DCS Positionable. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:GetAltitude() + self:F2() + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePointVec3 = DCSPositionable:getPoint() --DCSTypes#Vec3 + return PositionablePointVec3.y + end + + return nil +end + +--- Returns if the Positionable is located above a runway. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if Positionable is above a runway. +-- @return #nil The DCS Positionable is not existing or alive. +function POSITIONABLE:IsAboveRunway() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + + local PointVec2 = self:GetPointVec2() + local SurfaceType = land.getSurfaceType( PointVec2 ) + local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY + + self:T2( IsAboveRunway ) + return IsAboveRunway + end + + return nil +end + + + +--- Returns the DCS Positionable heading. +-- @param Positionable#POSITIONABLE self +-- @return #number The DCS Positionable 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 + self:T2( PositionableHeading ) + return PositionableHeading + end + end + + return nil +end + + +--- Returns true if the DCS Positionable is in the air. +-- @param Positionable#POSITIONABLE self +-- @return #boolean true if in the air. +-- @return #nil The DCS 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 DCS Positionable velocity vector. +-- @param Positionable#POSITIONABLE self +-- @return DCSTypes#Vec3 The velocity vector +-- @return #nil The DCS 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 + + + +--- This module contains the CONTROLLABLE class. +-- +-- 1) @{Controllable#CONTROLLABLE} class, extends @{Positionable#POSITIONABLE} +-- =========================================================== +-- The @{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 @{Controllable#CONTROLLABLE.PushTask} or @{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 @{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 +-- @author FlightControl + +--- The CONTROLLABLE class +-- @type CONTROLLABLE +-- @extends Positionable#POSITIONABLE +-- @field DCSControllable#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 DCSControllable#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 + return self +end + +-- DCS Controllable methods support. + +--- Get the controller for the CONTROLLABLE. +-- @param #CONTROLLABLE self +-- @return 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 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 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 + SCHEDULER:New( 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 Controllable#CONTROLLABLE self +function CONTROLLABLE:SetTask( DCSTask, WaitTime ) + self:F2( { DCSTask } ) + + 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.setTask( Controller, DCSTask ) + + if not WaitTime then + WaitTime = 1 + end + SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) + + return self + end + + return nil +end + + +--- Return a condition section for a controlled task. +-- @param #CONTROLLABLE self +-- @param DCSTime#Time time +-- @param #string userFlag +-- @param #boolean userFlagValue +-- @param #string condition +-- @param DCSTime#Time duration +-- @param #number lastWayPoint +-- return DCSTask#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 DCSTask#Task DCSTask +-- @param #DCSStopCondition DCSStopCondition +-- @return DCSTask#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 DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} +-- @return DCSTask#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 DCSCommand#Command DCSCommand +-- @return DCSTask#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 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 DCSTask#Task +function CONTROLLABLE:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) + self:F2( { FromWayPoint, ToWayPoint, Index } ) + + 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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackControllable( AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- AttackControllable = { + -- id = 'AttackControllable', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 = { + unitId = AttackUnit:GetID(), + weaponType = WeaponType, + expend = WeaponExpend, + attackQty = AttackQty, + direction = Direction, + attackQtyLimit = AttackQtyLimit, + controllableAttack = ControllableAttack, + }, + }, + + self:T3( { DCSTask } ) + return DCSTask +end + + +--- (AIR) Delivering weapon at the point on the ground. +-- @param #CONTROLLABLE self +-- @param DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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:GetPointVec2() + 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 DCSTypes#Vec2 PointVec2 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) + self:F2( { self.ControllableName, PointVec2, 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 = PointVec2, + 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 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 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 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 DCSTask#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 DCSTask#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 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 @{Zone#ZONE_RADIUS). +-- @param #CONTROLLABLE self +-- @param 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:GetPointVec2() + 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 Controllable#CONTROLLABLE FollowControllable The controllable to be followed. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFollow( FollowControllable, PointVec3, LastWaypointIndex ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex } ) + +-- Follow = { +-- id = 'Follow', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. +-- @param DCSTypes#Vec3 PointVec3 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 DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEscort( FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) + self:F2( { self.ControllableName, FollowControllable, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) + +-- Escort = { +-- id = 'Escort', +-- params = { +-- controllableId = Controllable.ID, +-- pos = Vec3, +-- lastWptIndexFlag = boolean, +-- lastWptIndex = number, +-- engagementDistMax = Distance, +-- targetTypes = array of AttributeName, +-- } +-- } + + local LastWaypointIndexFlag = nil + if LastWaypointIndex then + LastWaypointIndexFlag = true + end + + local DCSTask + DCSTask = { id = 'Follow', + params = { + controllableId = FollowControllable:GetID(), + pos = PointVec3, + 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 DCSTypes#Vec2 PointVec2 The point to fire at. +-- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFireAtPoint( PointVec2, Radius ) + self:F2( { self.ControllableName, PointVec2, Radius } ) + + -- FireAtPoint = { + -- id = 'FireAtPoint', + -- params = { + -- point = Vec2, + -- radius = Distance, + -- } + -- } + + local DCSTask + DCSTask = { id = 'FireAtPoint', + params = { + point = PointVec2, + radius = Radius, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +--- (GROUND) Hold ground controllable from moving. +-- @param #CONTROLLABLE self +-- @return DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskFAC_AttackControllable( AttackControllable, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Designation, Datalink } ) + +-- FAC_AttackControllable = { +-- id = 'FAC_AttackControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_AttackControllable', + params = { + controllableId = AttackControllable:GetID(), + weaponType = WeaponType, + designation = Designation, + datalink = Datalink, + } + } + + self:T3( { DCSTask } ) + return DCSTask +end + +-- EN-ROUTE TASKS FOR AIRBORNE CONTROLLABLES + +--- (AIR) Engaging targets of defined types. +-- @param #CONTROLLABLE self +-- @param 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 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 DCSTask#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 DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. +-- @param DCSTypes#Distance Radius Radius of the zone. +-- @param 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) + self:F2( { self.ControllableName, PointVec2, Radius, TargetTypes, Priority } ) + +-- EngageTargetsInZone = { +-- id = 'EngageTargetsInZone', +-- params = { +-- point = Vec2, +-- zoneRadius = Distance, +-- targetTypes = array of AttributeName, +-- priority = number +-- } +-- } + + local DCSTask + DCSTask = { id = 'EngageTargetsInZone', + params = { + point = PointVec2, + 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 Controllable#CONTROLLABLE AttackControllable 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 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 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskEngageControllable( AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) + self:F2( { self.ControllableName, AttackControllable, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) + + -- EngageControllable = { + -- id = 'EngageControllable ', + -- params = { + -- controllableId = Controllable.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 = { + controllableId = AttackControllable: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 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 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 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 DCSTask#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 DCSTask#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 DCSTask#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 DCSTask#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 Controllable#CONTROLLABLE AttackControllable 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 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 DCSTask#Task The DCS task structure. +function CONTROLLABLE:EnRouteTaskFAC_EngageControllable( AttackControllable, Priority, WeaponType, Designation, Datalink ) + self:F2( { self.ControllableName, AttackControllable, WeaponType, Priority, Designation, Datalink } ) + +-- FAC_EngageControllable = { +-- id = 'FAC_EngageControllable', +-- params = { +-- controllableId = Controllable.ID, +-- weaponType = number, +-- designation = enum AI.Task.Designation, +-- datalink = boolean, +-- priority = number, +-- } +-- } + + local DCSTask + DCSTask = { id = 'FAC_EngageControllable', + params = { + controllableId = AttackControllable: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 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 DCSTask#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 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 DCSTask#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 DCSTypes#Vec2 Point The point where to wait. +-- @param #number Radius The radius of the embarking zone around the Point. +-- @return DCSTask#Task The DCS task structure. +function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius ) + self:F2( { self.ControllableName, Point, Radius } ) + + local DCSTask --DCSTask#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 DCSTask#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 DCSTask#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 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 ):GetPointVec2() + + 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 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 ControllablePoint = self:GetUnit( 1 ):GetPointVec3() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.z + PointFrom.alt = ControllablePoint.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 ) + SCHEDULER:New( 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 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:GetPointVec2() + + 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:GetPointVec2() + 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 @{Airbase#AIRBASE} +-- A speed can be given in km/h. +-- A given formation can be given. +-- @param #CONTROLLABLE self +-- @param Airbase#AIRBASE ReturnAirbase The @{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:GetPointVec2() + 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:GetPointVec2() + + 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 @{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 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 Controllable#CONTROLLABLE self +-- @return 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 @{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 ) + + if WayPoints then + self.WayPoints = WayPoints + else + self.WayPoints = self:GetTaskRoute() + end + + return self +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 = CONTROLLABLE: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 ) + + 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 + + --- This module contains the SCHEDULER class. -- -- 1) @{Scheduler#SCHEDULER} class, extends @{Base#BASE} @@ -3251,8 +6056,10 @@ function SCHEDULER:_Scheduler() local ErrorHandler = function( errmsg ) env.info( "Error in SCHEDULER function:" .. errmsg ) - env.info( debug.traceback() ) - + if debug ~= nil then + env.info( debug.traceback() ) + end + return errmsg end @@ -3771,7 +6578,8 @@ function EVENT:OnPlayerLeaveUnit( EventFunction, EventSelf ) end - +--- @param #EVENT self +-- @param #EVENTDATA Event function EVENT:onEvent( Event ) self:F2( { _EVENTCODES[Event.id], Event } ) @@ -3805,7 +6613,7 @@ function EVENT:onEvent( Event ) Event.WeaponName = Event.Weapon:getTypeName() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end - self:E( { _EVENTCODES[Event.id], Event } ) + self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } ) for ClassName, EventData in pairs( self.Events[Event.id] ) do if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } ) @@ -4190,8 +6998,8 @@ function MENU_COALITION_COMMAND:Remove() end --- This module contains the GROUP class. -- --- 1) @{Group#GROUP} class, extends @{Base#BASE} --- ============================================= +-- 1) @{Group#GROUP} class, extends @{Controllable#CONTROLLABLE} +-- ============================================================= -- The @{Group#GROUP} class is a wrapper class to handle the DCS Group objects: -- -- * Support all DCS Group APIs. @@ -4339,28 +7147,18 @@ end --- The GROUP class -- @type GROUP --- @extends Base#BASE --- @field DCSGroup#Group DCSGroup The DCS group class. +-- @extends Controllable#CONTROLLABLE -- @field #string GroupName The name of the group. GROUP = { ClassName = "GROUP", - GroupName = "", - GroupID = 0, - Controller = nil, - DCSGroup = nil, - WayPointFunctions = {}, } ---- A DCSGroup --- @type DCSGroup --- @field id_ The ID of the group in DCS - --- Create a new GROUP from a DCSGroup -- @param #GROUP self -- @param DCSGroup#Group GroupName The DCS Group name -- @return #GROUP self function GROUP:Register( GroupName ) - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self:F2( GroupName ) self.GroupName = GroupName return self @@ -4395,7 +7193,7 @@ end --- Returns the DCS Group. -- @param #GROUP self -- @return DCSGroup#Group The DCS Group. -function GROUP:GetDCSGroup() +function GROUP:GetDCSObject() local DCSGroup = Group.getByName( self.GroupName ) if DCSGroup then @@ -4413,7 +7211,7 @@ end function GROUP:IsAlive() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupIsAlive = DCSGroup:isExist() @@ -4431,7 +7229,7 @@ end function GROUP:Destroy() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then for Index, UnitData in pairs( DCSGroup:getUnits() ) do @@ -4450,7 +7248,7 @@ end function GROUP:GetCategory() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() self:T3( GroupCategory ) @@ -4466,7 +7264,7 @@ end function GROUP:GetCategoryName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local CategoryNames = { [Group.Category.AIRPLANE] = "Airplane", @@ -4490,7 +7288,7 @@ end function GROUP:GetCoalition() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCoalition = DCSGroup:getCoalition() self:T3( GroupCoalition ) @@ -4507,7 +7305,7 @@ end function GROUP:GetCountry() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCountry = DCSGroup:getUnit(1):getCountry() self:T3( GroupCountry ) @@ -4517,40 +7315,6 @@ function GROUP:GetCountry() return nil end ---- Returns the name of the DCS Group. --- @param #GROUP self --- @return #string The DCS Group name. -function GROUP:GetName() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupName = DCSGroup:getName() - self:T3( GroupName ) - return GroupName - end - - return nil -end - ---- Returns the DCS Group identifier. --- @param #GROUP self --- @return #number The identifier of the DCS Group. -function GROUP:GetID() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupID = DCSGroup:getID() - self:T3( GroupID ) - return GroupID - 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 @@ -4559,7 +7323,7 @@ end function GROUP:GetUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) ) @@ -4579,7 +7343,7 @@ end function GROUP:GetDCSUnit( UnitNumber ) self:F2( { self.GroupName, UnitNumber } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnitFound = DCSGroup:getUnit( UnitNumber ) @@ -4596,7 +7360,7 @@ end -- @return #number The DCS Group size. function GROUP:GetSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupSize = DCSGroup:getSize() @@ -4614,7 +7378,7 @@ end -- @return #number The DCS Group initial size. function GROUP:GetInitialSize() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupInitialSize = DCSGroup:getInitialSize() @@ -4630,7 +7394,7 @@ end -- @return #table The UNITs wrappers. function GROUP:GetUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -4651,7 +7415,7 @@ end -- @return #table The DCS Units. function GROUP:GetDCSUnits() self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local DCSUnits = DCSGroup:getUnits() @@ -4662,117 +7426,13 @@ function GROUP:GetDCSUnits() return nil end ---- Get the controller for the GROUP. --- @param #GROUP self --- @return DCSController#Controller -function GROUP:_GetController() - self:F2( { self.GroupName } ) - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupController = DCSGroup:getController() - self:T3( GroupController ) - return GroupController - end - - return nil -end - - ---- Retrieve the group mission and allow to place function hooks within the mission waypoint plan. --- Use the method @{Group#GROUP:WayPointFunction} to define the hook functions for specific waypoints. --- Use the method @{Group@GROUP:WayPointExecute) to start the execution of the new mission plan. --- Note that when WayPointInitialize is called, the Mission of the group is RESTARTED! --- @param #GROUP self --- @param #table WayPoints If WayPoints is given, then use the route. --- @return #GROUP -function GROUP:WayPointInitialize( WayPoints ) - - if WayPoints then - self.WayPoints = WayPoints - else - self.WayPoints = self:GetTaskRoute() - end - - return self -end - - ---- Registers a waypoint function that will be executed when the group moves over the WayPoint. --- @param #GROUP 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 group moves over the waypoint. The waypoint function takes variable parameters. --- @return #GROUP -function GROUP: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 GROUP:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments ) - self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } ) - - local DCSTask - - local DCSScript = {} - DCSScript[#DCSScript+1] = "local MissionGroup = GROUP:Find( ... ) " - - if FunctionArguments and #FunctionArguments > 0 then - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup, " .. table.concat( FunctionArguments, "," ) .. ")" - else - DCSScript[#DCSScript+1] = FunctionString .. "( MissionGroup )" - 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 group will be 1! --- @param #GROUP 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 #GROUP -function GROUP:WayPointExecute( 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 - --- Activates a GROUP. -- @param #GROUP self function GROUP:Activate() self:F2( { self.GroupName } ) - trigger.action.activateGroup( self:GetDCSGroup() ) - return self:GetDCSGroup() + trigger.action.activateGroup( self:GetDCSObject() ) + return self:GetDCSObject() end @@ -4782,7 +7442,7 @@ end function GROUP:GetTypeName() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupTypeName = DCSGroup:getUnit(1):getTypeName() @@ -4799,7 +7459,7 @@ end function GROUP:GetCallsign() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCallSign = DCSGroup:getUnit(1):getCallsign() @@ -4811,11 +7471,14 @@ function GROUP:GetCallsign() end --- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group. +-- @param #GROUP self -- @return DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group. function GROUP:GetPointVec2() self:F2( self.GroupName ) - local GroupPointVec2 = self:GetUnit(1):GetPointVec2() + local UnitPoint = self:GetUnit(1) + UnitPoint:GetPointVec2() + local GroupPointVec2 = UnitPoint:GetPointVec2() self:T3( GroupPointVec2 ) return GroupPointVec2 end @@ -4893,7 +7556,7 @@ end function GROUP:IsAir() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local IsAirResult = DCSGroup:getCategory() == Group.Category.AIRPLANE or DCSGroup:getCategory() == Group.Category.HELICOPTER @@ -4910,7 +7573,7 @@ end function GROUP:IsHelicopter() self:F2( self.GroupName ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4927,7 +7590,7 @@ end function GROUP:IsAirPlane() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4944,7 +7607,7 @@ end function GROUP:IsGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4961,7 +7624,7 @@ end function GROUP:IsShip() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local GroupCategory = DCSGroup:getCategory() @@ -4979,7 +7642,7 @@ end function GROUP:AllOnGround() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local AllOnGroundResult = true @@ -5004,7 +7667,7 @@ end function GROUP:GetMaxVelocity() self:F2() - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then local MaxVelocity = 0 @@ -5043,1478 +7706,6 @@ function GROUP:GetMaxHeight() end --- Tasks - ---- Popping current Task from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PopCurrentTask() - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:popTask() - return self - end - - return nil -end - ---- Pushing Task on the queue from the group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:PushTask( DCSTask, WaitTime ) - self:F2() - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller:pushTask( DCSTask ) - - if WaitTime then - --routines.scheduleFunction( Controller.pushTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( 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 group. --- @param #GROUP self --- @return Group#GROUP self -function GROUP:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local Controller = self:_GetController() - - -- When a group SPAWNs, it takes about a second to get the group in the simulator. Setting tasks to unspawned groups provides unexpected results. - -- Therefore we schedule the functions to set the mission and options for the Group. - -- Controller.setTask( Controller, DCSTask ) - - if not WaitTime then - WaitTime = 1 - end - --routines.scheduleFunction( Controller.setTask, { Controller, DCSTask }, timer.getTime() + WaitTime ) - SCHEDULER:New( Controller, Controller.setTask, { DCSTask }, WaitTime ) - - return self - end - - return nil -end - - ---- Return a condition section for a controlled task. --- @param #GROUP self --- @param DCSTime#Time time --- @param #string userFlag --- @param #boolean userFlagValue --- @param #string condition --- @param DCSTime#Time duration --- @param #number lastWayPoint --- return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#Task DCSTask --- @param #DCSStopCondition DCSStopCondition --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSTask#TaskArray DCSTasks Array of @{DCSTask#Task} --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param DCSCommand#Command DCSCommand --- @return #GROUP self -function GROUP:SetCommand( DCSCommand ) - self:F2( DCSCommand ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Controller = self:_GetController() - Controller:setCommand( DCSCommand ) - return self - end - - return nil -end - ---- Perform a switch waypoint command --- @param #GROUP self --- @param #number FromWayPoint --- @param #number ToWayPoint --- @return DCSTask#Task -function GROUP:CommandSwitchWayPoint( FromWayPoint, ToWayPoint, Index ) - self:F2( { FromWayPoint, ToWayPoint, Index } ) - - local CommandSwitchWayPoint = { - id = 'SwitchWaypoint', - params = { - fromWaypointIndex = FromWayPoint, - goToWaypointIndex = ToWayPoint, - }, - } - - self:T3( { CommandSwitchWayPoint } ) - return CommandSwitchWayPoint -end - ---- Perform stop route command --- @param #GROUP self --- @param #boolean StopRoute --- @return DCSTask#Task -function GROUP:CommandStopRoute( StopRoute, Index ) - self:F2( { StopRoute, Index } ) - - local CommandStopRoute = { - id = 'StopRoute', - params = { - value = StopRoute, - }, - } - - self:T3( { CommandStopRoute } ) - return CommandStopRoute -end - - --- TASKS FOR AIR GROUPS - - ---- (AIR) Attack a Group. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackGroup( AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- AttackGroup = { - -- id = 'AttackGroup', - -- 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 = 'AttackGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackUnit( AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- AttackUnit = { - -- id = 'AttackUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- } - -- } - - local DCSTask - DCSTask = { id = 'AttackUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon at the point on the ground. --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombing( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- Bombing = { --- id = 'Bombing', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'Bombing', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - 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 #GROUP self --- @param 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 #GROUP self -function GROUP:TaskOrbitCircleAtVec2( Point, Altitude, Speed ) - self:F2( { self.GroupName, 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 group at a specified alititude. --- @param #GROUP self --- @param #number Altitude The altitude to hold the position. --- @param #number Speed The speed flying when holding the position. --- @return #GROUP self -function GROUP:TaskOrbitCircle( Altitude, Speed ) - self:F2( { self.GroupName, Altitude, Speed } ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local GroupPoint = self:GetPointVec2() - return self:TaskOrbitCircleAtVec2( GroupPoint, Altitude, Speed ) - end - - return nil -end - - - ---- (AIR) Hold position at the current position of the first unit of the group. --- @param #GROUP self --- @param #number Duration The maximum duration in seconds to hold the position. --- @return #GROUP self -function GROUP:TaskHoldPosition() - self:F2( { self.GroupName } ) - - return self:TaskOrbitCircle( 30, 10 ) -end - - - - ---- (AIR) Attacking the map object (building, structure, e.t.c). --- @param #GROUP self --- @param DCSTypes#Vec2 PointVec2 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskAttackMapObject( PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- AttackMapObject = { --- id = 'AttackMapObject', --- params = { --- point = Vec2, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'AttackMapObject', - params = { - point = PointVec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Delivering weapon on the runway. --- @param #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskBombingRunway( Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack ) - self:F2( { self.GroupName, Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack } ) - --- BombingRunway = { --- id = 'BombingRunway', --- params = { --- runwayId = AirdromeId, --- weaponType = number, --- expend = enum AI.Task.WeaponExpend, --- attackQty = number, --- direction = Azimuth, --- groupAttack = boolean, --- } --- } - - local DCSTask - DCSTask = { id = 'BombingRunway', - params = { - point = Airbase:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - groupAttack = GroupAttack, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Refueling from the nearest tanker. No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskRefueling() - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @param DCSTypes#Vec2 Point The point where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtVec2( Point, Duration ) - self:F2( { self.GroupName, 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 group at a @{Zone#ZONE_RADIUS). --- @param #GROUP self --- @param Zone#ZONE Zone The zone where to land. --- @param #number Duration The duration in seconds to stay on the ground. --- @return #GROUP self -function GROUP:TaskLandAtZone( Zone, Duration, RandomPoint ) - self:F2( { self.GroupName, Zone, Duration, RandomPoint } ) - - local Point - if RandomPoint then - Point = Zone:GetRandomVec2() - else - Point = Zone:GetPointVec2() - end - - local DCSTask = self:TaskLandAtVec2( Point, Duration ) - - self:T3( DCSTask ) - return DCSTask -end - - - ---- (AIR) Following another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- If another group is on land the unit / group will orbit around. --- @param #GROUP self --- @param Group#GROUP FollowGroup The group to be followed. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFollow( FollowGroup, PointVec3, LastWaypointIndex ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex } ) - --- Follow = { --- id = 'Follow', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - lastWptIndexFlag = LastWaypointIndexFlag, - lastWptIndex = LastWaypointIndex, - }, - }, - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (AIR) Escort another airborne group. --- The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. --- The unit / group will also protect that group from threats of specified types. --- @param #GROUP self --- @param Group#GROUP EscortGroup The group to be escorted. --- @param DCSTypes#Vec3 PointVec3 Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around. --- @param #number LastWaypointIndex Detach waypoint of another group. Once reached the unit / group Follow task is finished. --- @param #number EngagementDistanceMax Maximal distance from escorted group to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. --- @param DCSTypes#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEscort( FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes ) - self:F2( { self.GroupName, FollowGroup, PointVec3, LastWaypointIndex, EngagementDistance, TargetTypes } ) - --- Escort = { --- id = 'Escort', --- params = { --- groupId = Group.ID, --- pos = Vec3, --- lastWptIndexFlag = boolean, --- lastWptIndex = number, --- engagementDistMax = Distance, --- targetTypes = array of AttributeName, --- } --- } - - local LastWaypointIndexFlag = nil - if LastWaypointIndex then - LastWaypointIndexFlag = true - end - - local DCSTask - DCSTask = { id = 'Follow', - params = { - groupId = FollowGroup:GetID(), - pos = PointVec3, - 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 The point to fire at. --- @param DCSTypes#Distance Radius The radius of the zone to deploy the fire at. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskFireAtPoint( PointVec2, Radius ) - self:F2( { self.GroupName, PointVec2, Radius } ) - - -- FireAtPoint = { - -- id = 'FireAtPoint', - -- params = { - -- point = Vec2, - -- radius = Distance, - -- } - -- } - - local DCSTask - DCSTask = { id = 'FireAtPoint', - params = { - point = PointVec2, - radius = Radius, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (GROUND) Hold ground group from moving. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskHold() - self:F2( { self.GroupName } ) - --- Hold = { --- id = 'Hold', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Hold', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- TASKS FOR AIRBORNE AND GROUND UNITS/GROUPS - ---- (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @param #number WeaponType Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Designation, Datalink } ) - --- FAC_AttackGroup = { --- id = 'FAC_AttackGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_AttackGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - --- EN-ROUTE TASKS FOR AIRBORNE GROUPS - ---- (AIR) Engaging targets of defined types. --- @param #GROUP self --- @param 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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority ) - self:F2( { self.GroupName, 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 #GROUP self --- @param DCSTypes#Vec2 PointVec2 2D-coordinates of the zone. --- @param DCSTypes#Distance Radius Radius of the zone. --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageTargets( PointVec2, Radius, TargetTypes, Priority ) - self:F2( { self.GroupName, PointVec2, Radius, TargetTypes, Priority } ) - --- EngageTargetsInZone = { --- id = 'EngageTargetsInZone', --- params = { --- point = Vec2, --- zoneRadius = Distance, --- targetTypes = array of AttributeName, --- priority = number --- } --- } - - local DCSTask - DCSTask = { id = 'EngageTargetsInZone', - params = { - point = PointVec2, - zoneRadius = Radius, - targetTypes = TargetTypes, - priority = Priority - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- @param #GROUP self --- @param Group#GROUP AttackGroup The Group 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction. --- @param DCSTypes#Distance Altitude (optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit ) - self:F2( { self.GroupName, AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit } ) - - -- EngageGroup = { - -- id = 'EngageGroup ', - -- 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 = 'EngageGroup', - 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 #GROUP self --- @param 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 DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion. --- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo. --- @param DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks. --- @param #boolean GroupAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft. --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEngageUnit( AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack ) - self:F2( { self.GroupName, AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack } ) - - -- EngageUnit = { - -- id = 'EngageUnit', - -- params = { - -- unitId = Unit.ID, - -- weaponType = number, - -- expend = enum AI.Task.WeaponExpend - -- attackQty = number, - -- direction = Azimuth, - -- attackQtyLimit = boolean, - -- groupAttack = boolean, - -- priority = number, - -- } - -- } - - local DCSTask - DCSTask = { id = 'EngageUnit', - params = { - unitId = AttackUnit:GetID(), - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - attackQtyLimit = AttackQtyLimit, - groupAttack = GroupAttack, - 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskAWACS( ) - self:F2( { self.GroupName } ) - --- 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 #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskTanker( ) - self:F2( { self.GroupName } ) - --- Tanker = { --- id = 'Tanker', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'Tanker', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for ground units/groups - ---- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters. --- @param #GROUP self --- @return DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskEWR( ) - self:F2( { self.GroupName } ) - --- EWR = { --- id = 'EWR', --- params = { --- } --- } - - local DCSTask - DCSTask = { id = 'EWR', - params = { - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - --- En-route tasks for airborne and ground units/groups - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param Group#GROUP AttackGroup Target GROUP. --- @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 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink ) - self:F2( { self.GroupName, AttackGroup, WeaponType, Priority, Designation, Datalink } ) - --- FAC_EngageGroup = { --- id = 'FAC_EngageGroup', --- params = { --- groupId = Group.ID, --- weaponType = number, --- designation = enum AI.Task.Designation, --- datalink = boolean, --- priority = number, --- } --- } - - local DCSTask - DCSTask = { id = 'FAC_EngageGroup', - params = { - groupId = AttackGroup:GetID(), - weaponType = WeaponType, - designation = Designation, - datalink = Datalink, - priority = Priority, - } - } - - self:T3( { DCSTask } ) - return DCSTask -end - - ---- (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. --- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. --- If the task is assigned to the group lead unit will be a FAC. --- @param #GROUP self --- @param 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 DCSTask#Task The DCS task structure. -function GROUP:EnRouteTaskFAC( Radius, Priority ) - self:F2( { self.GroupName, 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 group to a Vec2 Point, wait for a defined duration and embark a group. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Duration The duration in seconds to wait. --- @param #GROUP EmbarkingGroup The group to be embarked. --- @return DCSTask#Task The DCS task structure -function GROUP:TaskEmbarking( Point, Duration, EmbarkingGroup ) - self:F2( { self.GroupName, Point, Duration, EmbarkingGroup.DCSGroup } ) - - local DCSTask - DCSTask = { id = 'Embarking', - params = { x = Point.x, - y = Point.y, - duration = Duration, - groupsForEmbarking = { EmbarkingGroup.GroupID }, - 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 group when arrived within a defined Radius. --- @param #GROUP self --- @param DCSTypes#Vec2 Point The point where to wait. --- @param #number Radius The radius of the embarking zone around the Point. --- @return DCSTask#Task The DCS task structure. -function GROUP:TaskEmbarkToTransport( Point, Radius ) - self:F2( { self.GroupName, Point, Radius } ) - - local DCSTask --DCSTask#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 #GROUP self --- @param #table TaskMission A table containing the mission task. --- @return DCSTask#Task -function GROUP: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 #GROUP self --- @param #table Points A table of route points. --- @return DCSTask#Task -function GROUP:TaskRoute( Points ) - self:F2( Points ) - - local DCSTask - DCSTask = { id = 'Mission', params = { route = { points = Points, }, }, } - - self:T3( { DCSTask } ) - return DCSTask -end - ---- (AIR + GROUND) Make the Group move to fly to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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 Group move to a given point. --- @param #GROUP self --- @param DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #GROUP self -function GROUP:TaskRouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local GroupPoint = self:GetUnit( 1 ):GetPointVec3() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.z - PointFrom.alt = GroupPoint.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 group to follow a given route. --- @param #GROUP self --- @param #table GoPoints A table of Route Points. --- @return #GROUP self -function GROUP:Route( GoPoints ) - self:F2( GoPoints ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - local Points = routines.utils.deepCopy( GoPoints ) - local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, } - local Controller = self:_GetController() - --Controller.setTask( Controller, MissionTask ) - --routines.scheduleFunction( Controller.setTask, { Controller, MissionTask}, timer.getTime() + 1 ) - SCHEDULER:New( Controller, Controller.setTask, { MissionTask }, 1 ) - return self - end - - return nil -end - - - ---- (AIR + GROUND) Route the group to a given zone. --- The group final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param 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 GROUP:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.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:GetPointVec2() - 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 Group to an @{Airbase#AIRBASE} --- A speed can be given in km/h. --- A given formation can be given. --- @param #GROUP self --- @param Airbase#AIRBASE ReturnAirbase The @{Airbase#AIRBASE} to return to. --- @param #number Speed (optional) The speed. --- @return #string The route -function GROUP: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 DCSGroup = self:GetDCSGroup() - - if DCSGroup then - - local GroupPoint = self:GetPointVec2() - local GroupVelocity = self:GetMaxVelocity() - - local PointFrom = {} - PointFrom.x = GroupPoint.x - PointFrom.y = GroupPoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = GroupVelocity - - - local PointTo = {} - local AirbasePoint = ReturnAirbase:GetPointVec2() - - 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 - --- @param Group#GROUP self function GROUP:Respawn( Template ) @@ -6549,26 +7740,6 @@ function GROUP:GetTemplate() end --- Commands - ---- Do Script command --- @param #GROUP self --- @param #string DoScript --- @return #DCSCommand -function GROUP:CommandDoScript( DoScript ) - - local DCSDoScript = { - id = "Script", - params = { - command = DoScript, - }, - } - - self:T3( DCSDoScript ) - return DCSDoScript -end - - --- Return the mission template of the group. -- @param #GROUP self -- @return #table The MissionTemplate @@ -6639,359 +7810,6 @@ function GROUP:CopyRoute( Begin, End, Randomize, Radius ) end -function GROUP:GetDetectedTargets() - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - return self:_GetController():getDetectedTargets() - end - - return nil -end - -function GROUP:IsTargetDetected( DCSObject ) - self:F2( self.GroupName ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP hold their weapons? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEHoldFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Holding weapons. --- @param Group#GROUP self --- @return Group#GROUP self -function GROUP:OptionROEHoldFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack returning on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEReturnFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Return fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEReturnFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack designated targets? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEOpenFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() or self:IsGround() or self:IsShip() then - return true - end - - return false - end - - return nil -end - ---- Openfire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEOpenFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP attack targets of opportunity? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROEWeaponFreePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Weapon free. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROEWeaponFree() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP ignore enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTNoReactionPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- No evasion on enemy threats. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTNoReaction() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade using passive defenses? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTPassiveDefensePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - ---- Evasion passive defense. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTPassiveDefense() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on enemy fire? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTEvadeFirePossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTEvadeFire() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 GROUP evade on fire using vertical manoeuvres? --- @param #GROUP self --- @return #boolean -function GROUP:OptionROTVerticalPossible() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup then - if self:IsAir() then - return true - end - - return false - end - - return nil -end - - ---- Evade on fire using vertical manoeuvres. --- @param #GROUP self --- @return #GROUP self -function GROUP:OptionROTVertical() - self:F2( { self.GroupName } ) - - local DCSGroup = self:GetDCSGroup() - if DCSGroup 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 - -- Message APIs --- Returns a message for a coalition or a client. @@ -7002,7 +7820,7 @@ end function GROUP:Message( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then return MESSAGE:New( Message, Duration, self:GetCallsign() .. " (" .. self:GetTypeName() .. ")" ) end @@ -7018,7 +7836,7 @@ end function GROUP:MessageToAll( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToAll() end @@ -7034,7 +7852,7 @@ end function GROUP:MessageToRed( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToRed() end @@ -7050,7 +7868,7 @@ end function GROUP:MessageToBlue( Message, Duration ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToBlue() end @@ -7067,7 +7885,7 @@ end function GROUP:MessageToClient( Message, Duration, Client ) self:F2( { Message, Duration } ) - local DCSGroup = self:GetDCSGroup() + local DCSGroup = self:GetDCSObject() if DCSGroup then self:Message( Message, Duration ):ToClient( Client ) end @@ -7076,8 +7894,8 @@ function GROUP:MessageToClient( Message, Duration, Client ) end --- This module contains the UNIT class. -- --- 1) @{Unit#UNIT} class, extends @{Base#BASE} --- =========================================== +-- 1) @{Unit#UNIT} class, extends @{Controllable#CONTROLLABLE} +-- =========================================================== -- The @{Unit#UNIT} class is a wrapper class to handle the DCS Unit objects: -- -- * Support all DCS Unit APIs. @@ -7150,18 +7968,11 @@ end --- The UNIT class -- @type UNIT --- @extends Base#BASE +-- @extends Controllable#CONTROLLABLE -- @field #UNIT.FlareColor FlareColor -- @field #UNIT.SmokeColor SmokeColor UNIT = { ClassName="UNIT", - CategoryName = { - [Unit.Category.AIRPLANE] = "Airplane", - [Unit.Category.HELICOPTER] = "Helicoper", - [Unit.Category.GROUND_UNIT] = "Ground Unit", - [Unit.Category.SHIP] = "Ship", - [Unit.Category.STRUCTURE] = "Structure", - }, FlareColor = { Green = trigger.flareColor.Green, Red = trigger.flareColor.Red, @@ -7196,13 +8007,10 @@ UNIT = { --- Create a new UNIT from DCSUnit. -- @param #UNIT self --- @param DCSUnit#Unit DCSUnit --- @param Database#DATABASE Database +-- @param #string UnitName The name of the DCS unit. -- @return Unit#UNIT function UNIT:Register( UnitName ) - - local self = BASE:Inherit( self, BASE:New() ) - self:F2( UnitName ) + local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) self.UnitName = UnitName return self end @@ -7230,7 +8038,10 @@ function UNIT:FindByName( UnitName ) return UnitFound end -function UNIT:GetDCSUnit() + +--- @param #UNIT self +-- @return DCSUnit#Unit +function UNIT:GetDCSObject() local DCSUnit = Unit.getByName( self.UnitName ) @@ -7241,78 +8052,8 @@ function UNIT:GetDCSUnit() return nil end ---- Returns coalition of the Unit. --- @param Unit#UNIT self --- @return DCSCoalitionObject#coalition.side The side of the coalition. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCoalition() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCoalition = DCSUnit:getCoalition() - self:T3( UnitCoalition ) - return UnitCoalition - end - - return nil -end - ---- Returns country of the Unit. --- @param Unit#UNIT self --- @return DCScountry#country.id The country identifier. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCountry() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCountry = DCSUnit:getCountry() - self:T3( UnitCountry ) - return UnitCountry - end - - return nil -end - - ---- Returns DCS Unit object name. --- The function provides access to non-activated units too. --- @param Unit#UNIT self --- @return #string The name of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitName = self.UnitName - return UnitName - end - - return nil -end ---- Returns if the unit is alive. --- @param Unit#UNIT self --- @return #boolean true if Unit is alive. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAlive() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitIsAlive = DCSUnit:isExist() - return UnitIsAlive - end - - return false -end --- Returns if the unit is activated. -- @param Unit#UNIT self @@ -7321,7 +8062,7 @@ end function UNIT:IsActive() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -7332,30 +8073,25 @@ function UNIT:IsActive() return nil end ---- Returns if the unit is located above a runway. +--- Returns the Unit's callsign - the localized string. -- @param Unit#UNIT self --- @return #boolean true if Unit is above a runway. +-- @return #string The Callsign of the Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:IsAboveRunway() +function UNIT:GetCallSign() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - - local PointVec2 = self:GetPointVec2() - local SurfaceType = land.getSurfaceType( PointVec2 ) - local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - - self:T2( IsAboveRunway ) - return IsAboveRunway + 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#UNIT self -- @return #string Player Name @@ -7363,7 +8099,7 @@ end function UNIT:GetPlayerName() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then @@ -7377,23 +8113,6 @@ function UNIT:GetPlayerName() return nil end ---- Returns the unit's unique identifier. --- @param Unit#UNIT self --- @return DCSUnit#Unit.ID Unit ID --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetID() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitID = DCSUnit:getID() - return UnitID - 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. @@ -7404,7 +8123,7 @@ end function UNIT:GetNumber() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitNumber = DCSUnit:getNumber() @@ -7421,7 +8140,7 @@ end function UNIT:GetGroup() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) @@ -7432,69 +8151,23 @@ function UNIT:GetGroup() end ---- Returns the unit's callsign - the localized string. +-- 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#UNIT self --- @return #string The Callsign of the Unit. +-- @return #string The name of the DCS Unit. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetCallSign() - self:F2( self.UnitName ) +function UNIT:GetPrefix() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitCallSign = DCSUnit:getCallsign() - return UnitCallSign - end - - return nil -end - ---- Returns the unit's health. Dead units has health <= 1.0. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife = DCSUnit:getLife() - return UnitLife - end - - return nil -end - ---- Returns the Unit's initial health. --- @param Unit#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:GetDCSUnit() - - if DCSUnit then - local UnitLife0 = DCSUnit:getLife0() - return UnitLife0 - end - - return 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#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:GetDCSUnit() - - if DCSUnit then - local UnitFuel = DCSUnit:getFuel() - return UnitFuel + local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) + self:T3( UnitPrefix ) + return UnitPrefix end return nil @@ -7507,7 +8180,7 @@ end function UNIT:GetAmmo() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitAmmo = DCSUnit:getAmmo() @@ -7524,7 +8197,7 @@ end function UNIT:GetSensors() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitSensors = DCSUnit:getSensors() @@ -7548,7 +8221,7 @@ end function UNIT:GetRadar() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitRadarOn, UnitRadarObject = DCSUnit:getRadar() @@ -7558,63 +8231,52 @@ function UNIT:GetRadar() return nil, nil end --- Need to add here functions to check if radar is on and which object etc. - ---- Returns unit descriptor. Descriptor type depends on unit category. +--- 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#UNIT self --- @return DCSUnit#Unit.Desc The Unit descriptor. +-- @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:GetDesc() +function UNIT:GetFuel() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitDesc = DCSUnit:getDesc() - self:T2( UnitDesc ) - return UnitDesc + local UnitFuel = DCSUnit:getFuel() + return UnitFuel end - self:E( "Unit " .. self.UnitName .. "not found!" ) return nil end - ---- Returns the type name of the DCS Unit. +--- Returns the unit's health. Dead units has health <= 1.0. -- @param Unit#UNIT self --- @return #string The type name of the DCS Unit. +-- @return #number The Unit's health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetTypeName() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() +function UNIT:GetLife() + self:F2( self.UnitName ) + + local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitTypeName = DCSUnit:getTypeName() - self:T3( UnitTypeName ) - return UnitTypeName + local UnitLife = DCSUnit:getLife() + return UnitLife end - - return nil + + return nil end - - ---- 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. +--- Returns the Unit's initial health. -- @param Unit#UNIT self --- @return #string The name of the DCS Unit. +-- @return #number The Unit's initial health value. -- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPrefix() - self:F2( self.UnitName ) +function UNIT:GetLife0() + self:F2( self.UnitName ) - local DCSUnit = self:GetDCSUnit() - + local DCSUnit = self:GetDCSObject() + if DCSUnit then - local UnitPrefix = string.match( self.UnitName, ".*#" ):sub( 1, -2 ) - self:T3( UnitPrefix ) - return UnitPrefix + local UnitLife0 = DCSUnit:getLife0() + return UnitLife0 end return nil @@ -7622,83 +8284,6 @@ end ---- Returns the @{DCSTypes#Vec2} vector indicating the point in 2D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec2 The 2D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec2() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - - local UnitPointVec2 = {} - UnitPointVec2.x = UnitPointVec3.x - UnitPointVec2.y = UnitPointVec3.z - - self:T2( UnitPointVec2 ) - return UnitPointVec2 - end - - return nil -end - - ---- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The 3D point vector of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPointVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPosition().p - self:T3( UnitPointVec3 ) - return UnitPointVec3 - end - - return nil -end - ---- Returns the @{DCSTypes#Position3} position vectors indicating the point and direction vectors in 3D of the DCS Unit within the mission. --- @param Unit#UNIT self --- @return DCSTypes#Position The 3D position vectors of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetPositionVec3() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPosition = DCSUnit:getPosition() - self:T3( UnitPosition ) - return UnitPosition - end - - return nil -end - ---- Returns the DCS Unit velocity vector. --- @param Unit#UNIT self --- @return DCSTypes#Vec3 The velocity vector --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetVelocity() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitVelocityVec3 = DCSUnit:getVelocity() - self:T3( UnitVelocityVec3 ) - return UnitVelocityVec3 - end - - return nil -end -- Is functions @@ -7736,40 +8321,6 @@ function UNIT:IsNotInZone( Zone ) end end ---- Returns true if the DCS Unit is in the air. --- @param Unit#UNIT self --- @return #boolean true if in the air. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:InAir() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitInAir = DCSUnit:inAir() - self:T3( UnitInAir ) - return UnitInAir - end - - return nil -end - ---- Returns the altitude of the DCS Unit. --- @param Unit#UNIT self --- @return DCSTypes#Distance The altitude of the DCS Unit. --- @return #nil The DCS Unit is not existing or alive. -function UNIT:GetAltitude() - self:F2() - - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitPointVec3 = DCSUnit:getPoint() --DCSTypes#Vec3 - return UnitPointVec3.y - end - - return nil -end --- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit. -- @param Unit#UNIT self @@ -7780,7 +8331,7 @@ end function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) self:F2( { self.UnitName, AwaitUnit.UnitName, Radius } ) - local DCSUnit = self:GetDCSUnit() + local DCSUnit = self:GetDCSObject() if DCSUnit then local UnitPos = self:GetPointVec3() @@ -7798,41 +8349,6 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius ) return nil end ---- Returns the DCS Unit category name as defined within the DCS Unit Descriptor. --- @param Unit#UNIT self --- @return #string The DCS Unit Category Name -function UNIT:GetCategoryName() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - local UnitCategoryName = self.CategoryName[ self:GetDesc().category ] - return UnitCategoryName - end - - return nil -end - ---- Returns the DCS Unit heading. --- @param Unit#UNIT self --- @return #number The DCS Unit heading -function UNIT:GetHeading() - local DCSUnit = self:GetDCSUnit() - - if DCSUnit then - - local UnitPosition = DCSUnit:getPosition() - if UnitPosition then - local UnitHeading = math.atan2( UnitPosition.x.z, UnitPosition.x.x ) - if UnitHeading < 0 then - UnitHeading = UnitHeading + 2 * math.pi - end - self:T2( UnitHeading ) - return UnitHeading - end - end - - return nil -end --- Signal a flare at the position of the UNIT. @@ -8422,33 +8938,34 @@ 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 DCSTypes#Vec2 PointVec2 The location to test. -- @return #boolean true if the location is within the zone. function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 ) self:F2( PointVec2 ) - local i - local j - local c = false + local Next + local Prev + local InPolygon = false - i = 1 - j = #self.Polygon + Next = 1 + Prev = #self.Polygon - while i < #self.Polygon do - j = i - i = i + 1 - self:T( { i, j, self.Polygon[i], self.Polygon[j] } ) - if ( ( ( self.Polygon[i].y > PointVec2.y ) ~= ( self.Polygon[j].y > PointVec2.y ) ) and - ( PointVec2.x < ( self.Polygon[j].x - self.Polygon[i].x ) * ( PointVec2.y - self.Polygon[i].y ) / ( self.Polygon[j].y - self.Polygon[i].y ) + self.Polygon[i].x ) + while Next <= #self.Polygon do + self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } ) + if ( ( ( self.Polygon[Next].y > PointVec2.y ) ~= ( self.Polygon[Prev].y > PointVec2.y ) ) and + ( PointVec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( PointVec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x ) ) then - c = not c + InPolygon = not InPolygon end - self:T2( { "c = ", c } ) + self:T2( { InPolygon = InPolygon } ) + Prev = Next + Next = Next + 1 end - self:T( { "c = ", c } ) - return c + self:T( { InPolygon = InPolygon } ) + return InPolygon end --- Define a random @{DCSTypes#Vec2} within the zone. @@ -9007,8 +9524,8 @@ function CLIENT:Message( Message, MessageDuration, MessageCategory, MessageInter end --- This module contains the STATIC class. -- --- 1) @{Static#STATIC} class, extends @{Unit#UNIT} --- =============================================== +-- 1) @{Static#STATIC} class, extends @{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 @{Static#STATIC} class is a wrapper class to handle the DCS Static objects: @@ -9045,7 +9562,7 @@ end --- The STATIC class -- @type STATIC --- @extends Unit#UNIT +-- @extends Positionable#POSITIONABLE STATIC = { ClassName = "STATIC", } @@ -9069,10 +9586,7 @@ function STATIC:FindByName( StaticName ) end function STATIC:Register( StaticName ) - local self = BASE:Inherit( self, UNIT:Register( StaticName ) ) - - self:F( StaticName ) - + local self = BASE:Inherit( self, POSITIONABLE:New( StaticName ) ) return self end @@ -9090,8 +9604,8 @@ end -- -- === -- --- 1) @{Airbase#AIRBASE} class, extends @{Base#BASE} --- ================================================= +-- 1) @{Airbase#AIRBASE} class, extends @{Positionable#POSITIONABLE} +-- ================================================================= -- The @{AIRBASE} class is a wrapper class to handle the DCS Airbase objects: -- -- * Support all DCS Airbase APIs. @@ -9137,7 +9651,7 @@ end --- The AIRBASE class -- @type AIRBASE --- @extends Base#BASE +-- @extends Positionable#POSITIONABLE AIRBASE = { ClassName="AIRBASE", CategoryName = { @@ -9151,13 +9665,11 @@ AIRBASE = { --- Create a new AIRBASE from DCSAirbase. -- @param #AIRBASE self --- @param DCSAirbase#Airbase DCSAirbase --- @param Database#DATABASE Database +-- @param #string AirbaseName The name of the airbase. -- @return Airbase#AIRBASE function AIRBASE:Register( AirbaseName ) - local self = BASE:Inherit( self, BASE:New() ) - self:F2( AirbaseName ) + local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) self.AirbaseName = AirbaseName return self end @@ -9515,6 +10027,8 @@ end function DATABASE:AddUnit( DCSUnitName ) if not self.UNITS[DCSUnitName] then + local UnitRegister = UNIT:Register( DCSUnitName ) + self:E( UnitRegister.UnitName ) self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) end @@ -9635,7 +10149,7 @@ function DATABASE:AddPlayer( UnitName, PlayerName ) if PlayerName then self:E( { "Add player for unit:", UnitName, PlayerName } ) - self.PLAYERS[PlayerName] = UNIT:FindByName( UnitName ) + self.PLAYERS[PlayerName] = self:FindUnit( UnitName ) self.PLAYERSJOINED[PlayerName] = PlayerName end end @@ -10413,6 +10927,15 @@ function SET_BASE:_Find( ObjectName ) end +--- Gets the Set. +-- @param #SET_BASE self +-- @return #SET_BASE self +function SET_BASE:GetSet() + self:F2() + + return self.Set +end + --- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. -- @param #SET_BASE self -- @param #string ObjectName @@ -10543,7 +11066,7 @@ end -- @param #SET_BASE self -- @param Event#EVENTDATA Event function SET_BASE:_EventOnDeadOrCrash( Event ) - self:F2( { Event } ) + self:F3( { Event } ) if Event.IniDCSUnit then local ObjectName, Object = self:FindInDatabase( Event ) @@ -10599,7 +11122,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen local function CoRoutine() local Count = 0 for ObjectID, Object in pairs( Set ) do - self:T2( Object ) + self:T3( Object ) if Function then if Function( unpack( FunctionArguments ), Object ) == true then IteratorFunction( Object, unpack( arg ) ) @@ -10688,7 +11211,7 @@ function SET_BASE:IsIncludeObject( Object ) return true end ---- Flushes the current SET_BASE contents in the log ... (for debug reasons). +--- 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() @@ -11309,7 +11832,6 @@ end function SET_UNIT:FindInDatabase( Event ) self:F3( { Event } ) - self:E( { Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] } ) return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end @@ -12350,6 +12872,10 @@ end Include.File( "Routines" ) Include.File( "Base" ) +Include.File( "Object" ) +Include.File( "Identifiable" ) +Include.File( "Positionable" ) +Include.File( "Controllable" ) Include.File( "Scheduler" ) Include.File( "Event" ) Include.File( "Menu" ) @@ -12388,6 +12914,7 @@ Include.File( "PatrolZone" ) Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) +Include.File( "FAC" ) -- The order of the declarations is important here. Don't touch it. @@ -14087,7 +14614,6 @@ function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) end self:T( "Routing " .. CargoHostName ) - --routines.scheduleFunction( routines.goRoute, { CargoHostName, Points}, timer.getTime() + 4 ) SCHEDULER:New( self, routines.goRoute, { CargoHostName, Points }, 4 ) return Valid @@ -17323,7 +17849,6 @@ function CLEANUP:New( ZoneNames, TimeInterval ) local self = BASE:Inherit( self, _EVENTDISPATCHER:OnBirth( self._OnEventBirth, self ) - --self.CleanUpScheduler = routines.scheduleFunction( self._CleanUpScheduler, { self }, timer.getTime() + 1, TimeInterval ) self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval ) return self @@ -17448,7 +17973,6 @@ function CLEANUP:_EventShot( Event ) if ( CurrentLandingZoneID ) then -- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon. --_SEADmissile:destroy() - --routines.scheduleFunction( CLEANUP._DestroyMissile, { self, Event.Weapon }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 ) end end @@ -17465,7 +17989,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.IniDCSUnit }, timer.getTime() + 0.1) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 ) end end @@ -17476,7 +17999,6 @@ function CLEANUP:_EventHitCleanUp( Event ) 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 ) - --routines.scheduleFunction( CLEANUP._DestroyUnit, { self, Event.TgtDCSUnit }, timer.getTime() + 0.1 ) SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 ) end end @@ -19038,7 +19560,6 @@ function SEAD:EventShot( Event ) local SEADUnitName = Event.IniDCSUnitName local SEADWeapon = Event.Weapon -- Identify the weapon fired local SEADWeaponName = Event.WeaponName -- return weapon type - --trigger.action.outText( string.format("Alerte, depart missile " ..string.format(SEADWeaponName)), 20) --debug message -- 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 @@ -19064,10 +19585,10 @@ function SEAD:EventShot( Event ) local Skills = { "Average", "Good", "High", "Excellent" } _targetskill = Skills[ math.random(1,4) ] end - self:T( _targetskill ) -- debug message for skill check + 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)) ) --debug message + 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)) @@ -19675,7 +20196,6 @@ function ESCORT:MenuReportTargets( Seconds ) self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu ) - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, Seconds ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds ) return self @@ -19897,7 +20417,6 @@ function ESCORT._SwitchReportNearbyTargets( MenuParam ) if self.ReportTargets then if not self.ReportTargetsScheduler then - --self.ReportTargetsScheduler = routines.scheduleFunction( self._ReportTargetsScheduler, { self }, timer.getTime() + 1, 30 ) self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, 30 ) end else @@ -19974,16 +20493,6 @@ function ESCORT._AttackTarget( MenuParam ) EscortGroup:OptionROEOpenFire() EscortGroup:OptionROTPassiveDefense() EscortGroup:SetState( EscortGroup, "Escort", self ) --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskAttackUnit( AttackUnit ), --- EscortGroup:TaskFunction( 1, 2, "_Resume", {"''"} ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -19994,15 +20503,6 @@ function ESCORT._AttackTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroup.PushTask, --- { EscortGroup, --- EscortGroup:TaskCombo( --- { EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroup, EscortGroup.PushTask, { EscortGroup:TaskCombo( @@ -20033,16 +20533,6 @@ function ESCORT._AssistTarget( MenuParam ) if EscortGroupAttack:IsAir() then EscortGroupAttack:OptionROEOpenFire() EscortGroupAttack:OptionROTVertical() --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskAttackUnit( AttackUnit ), --- EscortGroupAttack:TaskOrbitCircle( 500, 350 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -20053,15 +20543,6 @@ function ESCORT._AssistTarget( MenuParam ) }, 10 ) else --- routines.scheduleFunction( --- EscortGroupAttack.PushTask, --- { EscortGroupAttack, --- EscortGroupAttack:TaskCombo( --- { EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 ) --- } --- ) --- }, timer.getTime() + 10 --- ) SCHEDULER:New( EscortGroupAttack, EscortGroupAttack.PushTask, { EscortGroupAttack:TaskCombo( @@ -20121,7 +20602,6 @@ function ESCORT._ResumeMission( MenuParam ) table.remove( WayPoints, 1 ) end - --routines.scheduleFunction( EscortGroup.SetTask, {EscortGroup, EscortGroup:TaskRoute( WayPoints ) }, timer.getTime() + 1 ) SCHEDULER:New( EscortGroup, EscortGroup.SetTask, { EscortGroup:TaskRoute( WayPoints ) }, 1 ) EscortGroup:MessageToClient( "Resuming mission from waypoint " .. WayPoint .. ".", 10, EscortClient ) @@ -22564,9 +23044,64 @@ end -- === -- -- 1) @{Detection#DETECTION_BASE} class, extends @{Base#BASE} --- ===================================================== +-- ========================================================== -- The @{Detection#DETECTION_BASE} class defines the core functions to administer detected objects. --- Detected objects are grouped in SETS of UNITS. +-- +-- 1.1) DETECTION_BASE constructor +-- ------------------------------- +-- Construct a new DETECTION_BASE instance using the @{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: +-- +-- * @{Detection#DETECTION_BASE.InitDetectVisual}(): Detected using Visual. +-- * @{Detection#DETECTION_BASE.InitDetectOptical}(): Detected using Optical. +-- * @{Detection#DETECTION_BASE.InitDetectRadar}(): Detected using Radar. +-- * @{Detection#DETECTION_BASE.InitDetectIRST}(): Detected using IRST. +-- * @{Detection#DETECTION_BASE.InitDetectRWR}(): Detected using RWR. +-- * @{Detection#DETECTION_BASE.InitDetectDLINK}(): Detected using DLINK. +-- +-- 1.3) Obtain objects detected by DETECTION_BASE +-- ---------------------------------------------- +-- DETECTION_BASE builds @{Set}s of objects detected. These @{Set#SET_BASE}s can be retrieved using the method @{Detection#DETECTION_BASE.GetDetectedSets}(). +-- The method will return a list (table) of @{Set#SET_BASE} objects. +-- +-- === +-- +-- 2) @{Detection#DETECTION_UNITGROUPS} class, extends @{Detection#DETECTION_BASE} +-- =============================================================================== +-- The @{Detection#DETECTION_UNITGROUPS} class will detect units within the battle zone for a FAC group, +-- and will build a list (table) of @{Set#SET_UNIT}s containing the @{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 @{Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Detection#DETECTION_UNITGROUPS}. +-- +-- Retrieve the DetectedUnitSets with the method @{Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Set#SET_UNIT}s. +-- To understand the amount of sets created, use the method @{Detection#DETECTION_BASE.GetDetectedSetCount}(). +-- If you want to obtain a specific set from the DetectedSets, use the method @{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 @{Detection#DETECTION_BASE.GetDetectionZones}(). +-- To understand the amount of zones created, use the method @{Detection#DETECTION_BASE.GetDetectionZoneCount}(). +-- If you want to obtain a specific zone from the DetectedZones, use the method @{Detection#DETECTION_BASE.GetDetectionZone}() with a given index. +-- +-- 1.4) Flare or Smoke detected units +-- ---------------------------------- +-- Use the methods @{Detection#DETECTION_UNITGROUPS.FlareDetectedUnits}() or @{Detection#DETECTION_UNITGROUPS.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 @{Detection#DETECTION_UNITGROUPS.FlareDetectedZones}() or @{Detection#DETECTION_UNITGROUPS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place. +-- +-- === -- -- @module Detection -- @author Mechanic : Concept & Testing @@ -22578,148 +23113,640 @@ end -- @type DETECTION_BASE -- @field Group#GROUP FACGroup The GROUP in the Forward Air Controller role. -- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. --- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. --- @field #DETECTION_BASE.DetectedUnitSets DetectedUnitSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectedZoneRange. --- @field #DETECTION_BASE.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. --- @extends Set#SET_BASE +-- @field #DETECTION_BASE.DetectedSets DetectedSets A list of @{Set#SET_BASE}s containing the objects in each set that were detected. The base class will not build the detected sets, but will leave that to the derived classes. +-- @extends Base#BASE DETECTION_BASE = { ClassName = "DETECTION_BASE", - DetectedUnitSets = {}, - DetectedUnits = {}, + DetectedSets = {}, + DetectedObjects = {}, FACGroup = nil, DetectionRange = nil, - DetectionZoneRange = nil, } ---- @type DETECTION_BASE.DetectedUnitSets --- @list +--- @type DETECTION_BASE.DetectedSets +-- @list --- @type DETECTION_BASE.DetectedZones --- @list +-- @list --- DETECTION constructor. -- @param #DETECTION_BASE self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. -- @return #DETECTION_BASE self -function DETECTION_BASE:New( FACGroup, DetectionRange, DetectionZoneRange ) +function DETECTION_BASE:New( FACGroup, DetectionRange ) -- Inherits from BASE local self = BASE:Inherit( self, BASE:New() ) self.FACGroup = FACGroup self.DetectionRange = DetectionRange - self.DetectionZoneRange = DetectionZoneRange - self.DetectionScheduler = SCHEDULER:New(self, self._DetectionScheduler, { self, "Detection" }, 10, 30, 0.2 ) + self:InitDetectVisual( false ) + self:InitDetectOptical( false ) + self:InitDetectRadar( false ) + self:InitDetectRWR( false ) + self:InitDetectIRST( false ) + self:InitDetectDLINK( false ) + + return self end ---- Form @{Set}s of detected @{Unit#UNIT}s in an array of @{Set#SET_UNIT}s. +--- 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 + +--- Gets the FAC group. +-- @param #DETECTION_BASE self +-- @return Group#GROUP self +function DETECTION_BASE:GetFACGroup() + self:F2() + + return self.FACGroup +end + +--- Get the detected @{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 Set#SET_BASE +function DETECTION_BASE:GetDetectedSet( Index ) + + local DetectionSet = self.DetectedSets[Index] + if DetectionSet then + return DetectionSet + end + + return nil +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 @{Unit#UNIT}s in an array of @{Set#SET_BASE}s. -- @param #DETECTION_BASE self function DETECTION_BASE:_DetectionScheduler( SchedulerName ) self:F2( { SchedulerName } ) - self.DetectedUnitSets = {} + self.DetectedObjects = {} + self.DetectedSets = {} + self.DetectedZones = {} if self.FACGroup:IsAlive() then local FACGroupName = self.FACGroup:GetName() - local FACDetectedTargets = self.FACGroup:GetDetectedTargets() + + local FACDetectedTargets = self.FACGroup:GetDetectedTargets( + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) for FACDetectedTargetID, FACDetectedTarget in pairs( FACDetectedTargets ) do - local FACObject = FACDetectedTarget.object + local FACObject = FACDetectedTarget.object -- DCSObject#Object self:T2( FACObject ) if FACObject and FACObject:isExist() and FACObject.id_ < 50000000 then - local FACDetectedUnit = UNIT:Find( FACObject ) - local FACDetectedUnitName = FACDetectedUnit:GetName() + local FACDetectedObjectName = FACObject:getName() - local FACDetectedUnitPositionVec3 = FACDetectedUnit:GetPointVec3() + local FACDetectedObjectPositionVec3 = FACObject:getPoint() local FACGroupPositionVec3 = self.FACGroup:GetPointVec3() - local Distance = ( ( FACDetectedUnitPositionVec3.x - FACGroupPositionVec3.x )^2 + - ( FACDetectedUnitPositionVec3.y - FACGroupPositionVec3.y )^2 + - ( FACDetectedUnitPositionVec3.z - FACGroupPositionVec3.z )^2 + + local Distance = ( ( FACDetectedObjectPositionVec3.x - FACGroupPositionVec3.x )^2 + + ( FACDetectedObjectPositionVec3.y - FACGroupPositionVec3.y )^2 + + ( FACDetectedObjectPositionVec3.z - FACGroupPositionVec3.z )^2 ) ^ 0.5 / 1000 - self:T( { FACGroupName, FACDetectedUnitName, Distance } ) + self:T( { FACGroupName, FACDetectedObjectName, Distance } ) if Distance <= self.DetectionRange then - if not self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = {} + if not self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = {} end - self.DetectedUnits[FACDetectedUnitName].DetectedUnit = UNIT:FindByName( FACDetectedUnitName ) - self.DetectedUnits[FACDetectedUnitName].Visible = FACDetectedTarget.visible - self.DetectedUnits[FACDetectedUnitName].Type = FACDetectedTarget.type - self.DetectedUnits[FACDetectedUnitName].Distance = FACDetectedTarget.distance + self.DetectedObjects[FACDetectedObjectName].Name = FACDetectedObjectName + self.DetectedObjects[FACDetectedObjectName].Visible = FACDetectedTarget.visible + self.DetectedObjects[FACDetectedObjectName].Type = FACDetectedTarget.type + self.DetectedObjects[FACDetectedObjectName].Distance = FACDetectedTarget.distance else -- if beyond the DetectionRange then nullify... - if self.DetectedUnits[FACDetectedUnitName] then - self.DetectedUnits[FACDetectedUnitName] = nil + if self.DetectedObjects[FACDetectedObjectName] then + self.DetectedObjects[FACDetectedObjectName] = nil end end end end + + self:T2( self.DetectedObjects ) - -- okay, now we have a list of detected unit names ... + -- okay, now we have a list of detected object names ... -- Sort the table based on distance ... - self:T( { "Sorting DetectedUnits table:", self.DetectedUnits } ) - table.sort( self.DetectedUnits, function( a, b ) return a.Distance < b.Distance end ) - self:T( { "Sorted Targets Table:", self.DetectedUnits } ) + self:T( { "Sorting DetectedObjects table:", self.DetectedObjects } ) + table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end ) + self:T( { "Sorted Targets Table:", self.DetectedObjects } ) - -- Now group the DetectedUnits table into SET_UNITs, evaluating the DetectionZoneRange. + -- Now group the DetectedObjects table into SET_BASEs, evaluating the DetectionZoneRange. - if self.DetectedUnits then - for DetectedUnitName, DetectedUnitData in pairs( self.DetectedUnits ) do - local DetectedUnit = DetectedUnitData.DetectedUnit -- Unit#UNIT - if DetectedUnit and DetectedUnit:IsAlive() then - self:T( DetectedUnit:GetName() ) - if #self.DetectedUnitSets == 0 then - self:T( { "Adding Unit Set #", 1 } ) - self.DetectedUnitSets[1] = {} - self.DetectedUnitSets[1].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[1].Set = SET_UNIT:New() - self.DetectedUnitSets[1].Set:AddUnit( DetectedUnit ) - else - local AddedToSet = false - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - self:T( "Detected Unit Set #" .. DetectedUnitSetID ) - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - if DetectedUnit:IsInZone( DetectedZone ) then - self:T( "Adding to Unit Set #" .. DetectedUnitSetID ) - self.DetectedUnitSets[DetectedUnitSetID].Set:AddUnit( DetectedUnit ) - AddedToSet = true - end - end - if AddedToSet == false then - self:T( "Adding new Unit Set #" .. #self.DetectedUnitSets+1 ) - self.DetectedUnitSets[#self.DetectedUnitSets+1] = {} - self.DetectedUnitSets[#self.DetectedUnitSets].Zone = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) - self.DetectedUnitSets[#self.DetectedUnitSets].Set = SET_UNIT:New() - self.DetectedUnitSets[#self.DetectedUnitSets].Set:AddUnit( DetectedUnit ) - end - end - end - end + if self.DetectedObjects then + self:CreateDetectionSets() end - -- Now all the tests should have been build, now make some smoke and flares... - - for DetectedUnitSetID, DetectedUnitSetData in pairs( self.DetectedUnitSets ) do - local DetectedUnitSet = DetectedUnitSetData.Set -- Set#SET_UNIT - local DetectedZone = DetectedUnitSetData.Zone -- Zone#ZONE_UNIT - self:T( "Detected Set #" .. DetectedUnitSetID ) - DetectedUnitSet:ForEachUnit( - --- @param Unit#UNIT DetectedUnit - function( DetectedUnit ) - self:T( DetectedUnit:GetName() ) + + end +end + +--- @type DETECTION_UNITGROUPS.DetectedSets +-- @list +-- + + +--- @type DETECTION_UNITGROUPS.DetectedZones +-- @list +-- + + +--- DETECTION_UNITGROUPS class +-- @type DETECTION_UNITGROUPS +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @field #DETECTION_UNITGROUPS.DetectedSets DetectedSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectionZoneRange. +-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units. +-- @extends Detection#DETECTION_BASE +DETECTION_UNITGROUPS = { + ClassName = "DETECTION_UNITGROUPS", + DetectedZones = {}, +} + + + +--- DETECTION_UNITGROUPS constructor. +-- @param Detection#DETECTION_UNITGROUPS self +-- @param Group#GROUP FACGroup The GROUP in the Forward Air Controller role. +-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. +-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. +-- @return Detection#DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:New( FACGroup, DetectionRange, DetectionZoneRange ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New( FACGroup, DetectionRange ) ) + self.DetectionZoneRange = DetectionZoneRange + + self:Schedule( 10, 30 ) + + return self +end + +--- Get the detected @{Zone#ZONE_UNIT}s. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones +function DETECTION_UNITGROUPS:GetDetectedZones() + + local DetectedZones = self.DetectedZones + return DetectedZones +end + +--- Get the amount of @{Zone#ZONE_UNIT}s with detected units. +-- @param #DETECTION_UNITGROUPS self +-- @return #number Count +function DETECTION_UNITGROUPS:GetDetectedZoneCount() + + local DetectedZoneCount = #self.DetectedZones + return DetectedZoneCount +end + +--- Get a SET of detected objects using a given numeric index. +-- @param #DETECTION_UNITGROUPS self +-- @param #number Index +-- @return Zone#ZONE_UNIT +function DETECTION_UNITGROUPS:GetDetectedZone( Index ) + + local DetectedZone = self.DetectedZones[Index] + if DetectedZone then + return DetectedZone + end + + return nil +end + +--- Smoke the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedUnits() + self:F2() + + self._SmokeDetectedUnits = true + return self +end + +--- Flare the detected units +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedUnits() + self:F2() + + self._FlareDetectedUnits = true + return self +end + +--- Smoke the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:SmokeDetectedZones() + self:F2() + + self._SmokeDetectedZones = true + return self +end + +--- Flare the detected zones +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:FlareDetectedZones() + self:F2() + + self._FlareDetectedZones = true + return self +end + + +--- Make a DetectionSet table. This function will be overridden in the derived clsses. +-- @param #DETECTION_UNITGROUPS self +-- @return #DETECTION_UNITGROUPS self +function DETECTION_UNITGROUPS:CreateDetectionSets() + self:F2() + + for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do + self:T( DetectedUnitData.Name ) + local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT + if DetectedUnit and DetectedUnit:IsAlive() then + self:T( DetectedUnit:GetName() ) + if #self.DetectedSets == 0 then + self:T( { "Adding Unit Set #", 1 } ) + self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[1] = SET_UNIT:New() + self.DetectedSets[1]:AddUnit( DetectedUnit ) + else + local AddedToSet = false + for DetectedZoneIndex = 1, #self.DetectedZones do + self:T( "Detected Unit Set #" .. DetectedZoneIndex ) + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + if DetectedUnit:IsInZone( DetectedZone ) then + self:T( "Adding to Unit Set #" .. DetectedZoneIndex ) + DetectedUnitSet:AddUnit( DetectedUnit ) + AddedToSet = true + end + end + if AddedToSet == false then + local DetectedZoneIndex = #self.DetectedZones + 1 + self:T( "Adding new zone #" .. DetectedZoneIndex ) + self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) + self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New() + self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit ) + end + end + end + end + + -- Now all the tests should have been build, now make some smoke and flares... + + for DetectedZoneIndex = 1, #self.DetectedZones do + local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE + local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT + self:T( "Detected Set #" .. DetectedZoneIndex ) + DetectedUnitSet:ForEachUnit( + --- @param Unit#UNIT DetectedUnit + function( DetectedUnit ) + self:T( DetectedUnit:GetName() ) + if self._FlareDetectedUnits then DetectedUnit:FlareRed() end - ) + if self._SmokeDetectedUnits then + DetectedUnit:SmokeRed() + end + end + ) + if self._FlareDetectedZones then + DetectedZone:FlareZone( POINT_VEC3.SmokeColor.White, 30, math.random( 0,90 ) ) + end + if self._SmokeDetectedZones then DetectedZone:SmokeZone( POINT_VEC3.SmokeColor.White, 30 ) end end + end + + +--- This module contains the FAC classes. +-- +-- === +-- +-- 1) @{Fac#FAC_BASE} class, extends @{Base#BASE} +-- ============================================== +-- The @{Fac#FAC_BASE} class defines the core functions to report detected objects to clients. +-- Reportings can be done in several manners, and it is up to the derived classes if FAC_BASE to model the reporting behaviour. +-- +-- 1.1) FAC_BASE constructor: +-- ---------------------------- +-- * @{Fac#FAC_BASE.New}(): Create a new FAC_BASE instance. +-- +-- 1.2) FAC_BASE reporting: +-- ------------------------ +-- Derived FAC_BASE classes will reports detected units using the method @{Fac#FAC_BASE.ReportDetected}(). This method implements polymorphic behaviour. +-- +-- The time interval in seconds of the reporting can be changed using the methods @{Fac#FAC_BASE.SetReportInterval}(). +-- To control how long a reporting message is displayed, use @{Fac#FAC_BASE.SetReportDisplayTime}(). +-- Derived classes need to implement the method @{Fac#FAC_BASE.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. +-- +-- Reporting can be started and stopped using the methods @{Fac#FAC_BASE.StartReporting}() and @{Fac#FAC_BASE.StopReporting}() respectively. +-- If an ad-hoc report is requested, use the method @{Fac#FAC_BASE#ReportNow}(). +-- +-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds. +-- +-- === +-- +-- 2) @{Fac#FAC_REPORTING} class, extends @{Fac#FAC_BASE} +-- ====================================================== +-- The @{Fac#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Fac#FAC_BASE} class. +-- +-- 2.1) FAC_REPORTING constructor: +-- ------------------------------- +-- The @{Fac#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance. +-- +-- === +-- +-- @module Fac +-- @author Mechanic, Prof_Hilactic, FlightControl : Concept & Testing +-- @author FlightControl : Design & Programming + + + +--- FAC_BASE class. +-- @type FAC_BASE +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends Base#BASE +FAC_BASE = { + ClassName = "FAC_BASE", + ClientSet = nil, + Detection = nil, +} + +--- FAC constructor. +-- @param #FAC_BASE self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_BASE self +function FAC_BASE:New( ClientSet, Detection ) + + -- Inherits from BASE + local self = BASE:Inherit( self, BASE:New() ) -- Fac#FAC_BASE + + self.ClientSet = ClientSet + self.Detection = Detection + + self:SetReportInterval( 60 ) + self:SetReportDisplayTime( 15 ) + + return self +end + +--- Set the reporting time interval. +-- @param #FAC_BASE self +-- @param #number ReportInterval The interval in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportInterval( ReportInterval ) + self:F2() + + self._ReportInterval = ReportInterval +end + + +--- Set the reporting message display time. +-- @param #FAC_BASE self +-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done. +-- @return #FAC_BASE self +function FAC_BASE:SetReportDisplayTime( ReportDisplayTime ) + self:F2() + + self._ReportDisplayTime = ReportDisplayTime +end + +--- Get the reporting message display time. +-- @param #FAC_BASE self +-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done. +function FAC_BASE:GetReportDisplayTime() + self:F2() + + return self._ReportDisplayTime +end + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_BASE self +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #FAC_BASE self +function FAC_BASE:ReportDetected( DetectedSets ) + self:F2() + + + +end + +--- Schedule the FAC reporting. +-- @param #FAC_BASE 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 #FAC_BASE self +function FAC_BASE:Schedule( DelayTime, ReportInterval ) + self:F2() + + self._ScheduleDelayTime = DelayTime + + self:SetReportInterval( ReportInterval ) + + self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "Fac" }, self._ScheduleDelayTime, self._ReportInterval ) + return self +end + +--- Report the detected @{Unit#UNIT}s detected within the @{DetectION#DETECTION_BASE} object to the @{Set#SET_CLIENT}s. +-- @param #FAC_BASE self +function FAC_BASE:_FacScheduler( SchedulerName ) + self:F2( { SchedulerName } ) + + self.ClientSet:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + if Client:IsAlive() then + local DetectedSets = self.Detection:GetDetectedSets() + return self:ReportDetected( Client, DetectedSets ) + end + end + ) + + return true +end + +-- FAC_REPORTING + +--- FAC_REPORTING class. +-- @type FAC_REPORTING +-- @field Set#SET_CLIENT ClientSet The clients to which the FAC will report to. +-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. +-- @extends #FAC_BASE +FAC_REPORTING = { + ClassName = "FAC_REPORTING", +} + + +--- FAC_REPORTING constructor. +-- @param #FAC_REPORTING self +-- @param Set#SET_CLIENT ClientSet +-- @param Detection#DETECTION_BASE Detection +-- @return #FAC_REPORTING self +function FAC_REPORTING:New( ClientSet, Detection ) + + -- Inherits from FAC_BASE + local self = BASE:Inherit( self, FAC_BASE:New( ClientSet, Detection ) ) -- #FAC_REPORTING + + self:Schedule( 5, 60 ) + return self +end + + +--- Reports the detected items to the @{Set#SET_CLIENT}. +-- @param #FAC_REPORTING self +-- @param Client#CLIENT Client The @{Client} object to where the report needs to go. +-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. +-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. +function FAC_REPORTING:ReportDetected( Client, DetectedSets ) + self:F2( Client ) + + local DetectedMsg = {} + for DetectedUnitSetID, DetectedUnitSet in pairs( DetectedSets ) do + local UnitSet = DetectedUnitSet -- Set#SET_UNIT + local MT = {} -- Message Text + local UnitTypes = {} + for DetectedUnitID, DetectedUnitData in pairs( UnitSet:GetSet() ) do + local DetectedUnit = DetectedUnitData -- Unit#UNIT + local UnitType = DetectedUnit:GetTypeName() + if not UnitTypes[UnitType] then + UnitTypes[UnitType] = 1 + else + UnitTypes[UnitType] = UnitTypes[UnitType] + 1 + end + end + for UnitTypeID, UnitType in pairs( UnitTypes ) do + MT[#MT+1] = UnitType .. " of " .. UnitTypeID + end + local MessageText = table.concat( MT, ", " ) + DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedUnitSetID .. ": " .. MessageText + end + local FACGroup = self.Detection:GetFACGroup() + FACGroup:MessageToClient( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Client ) + + return true +end + + BASE:TraceOnOff( false ) env.info( '*** MOOSE INCLUDE END *** ' ) diff --git a/Moose Mission Setup/Moose_Create.bat b/Moose Mission Setup/Moose_Create.bat index 755389210..a6ebea40e 100644 --- a/Moose Mission Setup/Moose_Create.bat +++ b/Moose Mission Setup/Moose_Create.bat @@ -40,6 +40,10 @@ COPY /b Moose.lua + "Moose Create Static\Moose_Static_Loader.lua" Moose. COPY /b Moose.lua + %1\Routines.lua Moose.lua COPY /b Moose.lua + %1\Base.lua Moose.lua +COPY /b Moose.lua + %1\Object.lua Moose.lua +COPY /b Moose.lua + %1\Identifiable.lua Moose.lua +COPY /b Moose.lua + %1\Positionable.lua Moose.lua +COPY /b Moose.lua + %1\Controllable.lua Moose.lua COPY /b Moose.lua + %1\Scheduler.lua Moose.lua COPY /b Moose.lua + %1\Event.lua Moose.lua COPY /b Moose.lua + %1\Menu.lua Moose.lua @@ -78,6 +82,7 @@ COPY /b Moose.lua + %1\PatrolZone.lua Moose.lua COPY /b Moose.lua + %1\AIBalancer.lua Moose.lua COPY /b Moose.lua + %1\AirbasePolice.lua Moose.lua COPY /b Moose.lua + %1\Detection.lua Moose.lua +COPY /b Moose.lua + %1\FAC.lua Moose.lua COPY /b Moose.lua + "Moose Create Static\Moose_Trace_Off.lua" Moose.lua diff --git a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz index b51dfcbbe..f5743e2d5 100644 Binary files a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz and b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz differ diff --git a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz index ee87ab15c..a40541339 100644 Binary files a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz and b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz index dcaf24ee0..8939a96e8 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz index dc9a48785..89ee9770c 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz index 7615cb2ae..190fd65f9 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz differ diff --git a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz index 49f75907b..7b0bb991e 100644 Binary files a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz and b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz differ diff --git a/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz b/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz index 04b7ae103..c9ae54b5f 100644 Binary files a/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz and b/Moose Test Missions/Moose_Test_DESTROY/MOOSE_Test_DESTROY.miz differ diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.lua b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.lua index 9caae011f..d98bc2215 100644 --- a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.lua +++ b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.lua @@ -1,4 +1,5 @@ local FACGroup = GROUP:FindByName( "FAC Group" ) -local FACDetection = DETECTION_BASE:New( FACGroup, 1000, 250 ) \ No newline at end of file +local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ):SmokeDetectedZones():FlareDetectedUnits() + diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz index e38e6baec..d8636d2bd 100644 Binary files a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz and b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz differ diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.lua b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.lua new file mode 100644 index 000000000..37e62ae95 --- /dev/null +++ b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.lua @@ -0,0 +1,63 @@ + +local FACGroup = GROUP:FindByName( "FAC Group Lase" ) + +local FACDetection = DETECTION_BASE:New( FACGroup, 1000, 250 ) + + +local LaseScheduler = SCHEDULER:New(nil, + --- @param Group#GROUP FACGroup + -- @param Detection#DETECTION_BASE FACDetection + function( FACGroup, FACDetection ) + if FACDetection:GetDetectionUnitSetCount() > 0 then + local DetectedUnitSet = FACDetection:GetDetectionUnitSet(1) + if DetectedUnitSet then + FACDetection:E( { "I have a unit set ", DetectedUnitSet } ) + local FACUnit = FACGroup:GetUnit(1) + if FACUnit then + FACDetection:E( FACUnit ) + local FACDCSUnit = FACUnit:GetDCSUnit() + local FACUnitController = FACDCSUnit:getController() + DetectedUnitSet:ForEachUnit( + --- @param Unit#UNIT DetectedUnit + function( DetectedUnit, FACDCSUnit ) + FACDetection:E( DetectedUnit:GetDCSUnit() ) + FACDetection:E( FACDCSUnit ) + local JTAC = Spot.createInfraRed( FACDCSUnit, {x = 0, y = 2.0, z = 0}, DetectedUnit:GetPointVec3(), 1337) + end, FACDCSUnit + ) + end + end + end + end, { FACGroup, FACDetection }, + 30 + ) + +local LaseScheduler2 = SCHEDULER:New(nil, + --- @param Group#GROUP FACGroup + -- @param Detection#DETECTION_BASE FACDetection + function( FACGroup, FACDetection ) + if FACDetection:GetDetectionUnitSetCount() > 0 then + local DetectedUnitSet = FACDetection:GetDetectionUnitSet(1) + if DetectedUnitSet then + FACDetection:E( { "I have a unit set ", DetectedUnitSet } ) + local FACUnit = FACGroup:GetUnit(1) + if FACUnit then + FACDetection:E( FACUnit ) + local FACDCSUnit = FACUnit:GetDCSUnit() + local FACUnitController = FACDCSUnit:getController() + DetectedUnitSet:ForEachUnit( + --- @param Unit#UNIT DetectedUnit + function( DetectedUnit, FACDCSUnit ) + FACDetection:E( DetectedUnit:GetDCSUnit() ) + FACDetection:E( FACDCSUnit ) + local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity + = FACUnitController:isTargetDetected( DetectedUnit:GetDCSUnit(), Controller.Detection.IRST ) + FACDetection:E( { TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity } ) + end, FACDCSUnit + ) + end + end + end + end, { FACGroup, FACDetection }, + 40 + ) \ No newline at end of file diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz new file mode 100644 index 000000000..1d5a774d0 Binary files /dev/null and b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz differ diff --git a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua index 0af903907..58912b1bf 100644 --- a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua +++ b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.lua @@ -18,6 +18,7 @@ do :MenuSmoke() :MenuReportTargets( 60, 20 ) :MenuResumeMission() + :MenuROE() :MenuAssistedAttack() local EscortGroupArtillery = SpawnEscortArtillery:ReSpawn(1) diff --git a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz index 67402b0e0..5f4ee1984 100644 Binary files a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz and b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz differ diff --git a/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.lua b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.lua new file mode 100644 index 000000000..8e51ca4db --- /dev/null +++ b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.lua @@ -0,0 +1,8 @@ + + +local FACGroup = GROUP:FindByName( "FAC Group" ) + +local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ) +local FACClientSet = SET_CLIENT:New():FilterCoalitions( "blue" ):FilterStart() + +local FACReporting = FAC_REPORTING:New( FACClientSet, FACDetection ) \ No newline at end of file diff --git a/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz new file mode 100644 index 000000000..02ea77fa3 Binary files /dev/null and b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz differ diff --git a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz index 36b04e028..d91ec66b1 100644 Binary files a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz and b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz differ diff --git a/Moose Test Missions/Moose_Test_PATROLZONE/MOOSE_Test_PATROLZONE.miz b/Moose Test Missions/Moose_Test_PATROLZONE/MOOSE_Test_PATROLZONE.miz index e2e59094d..db3b2171d 100644 Binary files a/Moose Test Missions/Moose_Test_PATROLZONE/MOOSE_Test_PATROLZONE.miz and b/Moose Test Missions/Moose_Test_PATROLZONE/MOOSE_Test_PATROLZONE.miz differ diff --git a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz index 6906e080b..8942ee416 100644 Binary files a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz and b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz b/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz index 183e0bbed..b18755943 100644 Binary files a/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz and b/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz index ad1789241..5bd652aeb 100644 Binary files a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz and b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz index 928ebdd77..80907c6e5 100644 Binary files a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz and b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz index 4834e32a9..e52fe5d86 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz and b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz b/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz index e1dfb43fd..be33534cb 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz and b/Moose Test Missions/Moose_Test_SPAWN_Repeat/MOOSE_Test_SPAWN_Repeat.miz differ diff --git a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz index 1dfa11a42..ccb22ec8b 100644 Binary files a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz and b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz differ diff --git a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz index 872ac8d46..e2b82e9ab 100644 Binary files a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz and b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz index a0fd5873b..ac6114ce0 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz and b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz index ecd9294f0..8964c9fd2 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz and b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz index f3d1fb35c..c81572b99 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz and b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz index 1758a601d..17c016fea 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz and b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz differ diff --git a/Moose Training/Documentation/AIBalancer.html b/Moose Training/Documentation/AIBalancer.html index 267dbe1fd..c07c2ae71 100644 --- a/Moose Training/Documentation/AIBalancer.html +++ b/Moose Training/Documentation/AIBalancer.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Airbase.html b/Moose Training/Documentation/Airbase.html index 9d1bafccd..8e13e9b7f 100644 --- a/Moose Training/Documentation/Airbase.html +++ b/Moose Training/Documentation/Airbase.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • @@ -80,7 +86,7 @@
    -

    1) Airbase#AIRBASE class, extends Base#BASE

    +

    1) Airbase#AIRBASE class, extends Positionable#POSITIONABLE

    The AIRBASE class is a wrapper class to handle the DCS Airbase objects:

    - - -
    -
    - - DCSGroup#Group - -GROUP.DCSGroup - -
    -
    - -

    The DCS group class.

    -
    @@ -1253,341 +661,6 @@ So all event listeners will catch the destroy event of this DCS Group.

    - -GROUP:EnRouteTaskAWACS() - -
    -
    - -

    (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts).

    - - -

    No parameters.

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskEWR() - -
    -
    - -

    (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts).

    - - -

    No parameters.

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskEngageGroup(AttackGroup, Priority, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit) - -
    -
    - -

    (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.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP AttackGroup : -The Group to be attacked.

      - -
    • -
    • - -

      #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.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      DCSTypes#Distance Altitude : -(optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/aircraft will not attack from safe altitude.

      - -
    • -
    • - -

      #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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskEngageTargets(Distance, TargetTypes, Priority) - -
    -
    - -

    (AIR) Engaging targets of defined types.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Distance Distance : -Maximal distance from the target to a route leg. If the target is on a greater distance it will be ignored.

      - -
    • -
    • - -

      DCSTypes#AttributeNameArray TargetTypes : -Array of target categories allowed to engage.

      - -
    • -
    • - -

      #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 value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskEngageUnit(AttackUnit, Priority, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack) - -
    -
    - -

    (AIR) Attack the Unit.

    - -

    Parameters

    -
      -
    • - -

      Unit#UNIT AttackUnit : -The UNIT.

      - -
    • -
    • - -

      #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.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      #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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.

      - -
    • -
    • - -

      #boolean GroupAttack : -(optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskFAC(Radius, Priority) - -
    -
    - -

    (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.

    - - -

    The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. -If the task is assigned to the group lead unit will be a FAC.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Distance Radius : - The maximal distance from the FAC to a target.

      - -
    • -
    • - -

      #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 value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskFAC_EngageGroup(AttackGroup, Priority, WeaponType, Designation, Datalink) - -
    -
    - -

    (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.

    - - -

    The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. -If the task is assigned to the group lead unit will be a FAC.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP AttackGroup : -Target GROUP.

      - -
    • -
    • - -

      #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.

      - -
    • -
    • - -

      #number WeaponType : -Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.Designation Designation : -(optional) Designation type.

      - -
    • -
    • - -

      #boolean Datalink : -(optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:EnRouteTaskTanker() - -
    -
    - -

    (AIR) Aircraft will act as a tanker for friendly units.

    - - -

    No parameters.

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - GROUP:Find(DCSGroup) @@ -1742,8 +815,8 @@ The DCS Group is not existing or alive.

    - -GROUP:GetDCSGroup() + +GROUP:GetDCSObject()
    @@ -1808,37 +881,6 @@ The DCS Units.

    - -GROUP:GetDetectedTargets() - -
    -
    - - - -
    -
    -
    -
    - - -GROUP:GetID() - -
    -
    - -

    Returns the DCS Group identifier.

    - -

    Return value

    - -

    #number: -The identifier of the DCS Group.

    - -
    -
    -
    -
    - GROUP:GetInitialSize() @@ -1925,24 +967,6 @@ Minimum height found.

    - -GROUP:GetName() - -
    -
    - -

    Returns the name of the DCS Group.

    - -

    Return value

    - -

    #string: -The DCS Group name.

    - -
    -
    -
    -
    - GROUP:GetPointVec2() @@ -2110,20 +1134,6 @@ The UNIT wrapper class.

    #table: The UNITs wrappers.

    -
    -
    -
    -
    - - #number - -GROUP.GroupID - -
    -
    - - -
    @@ -2338,27 +1348,6 @@ true if DCS Group contains Ships.

    - -GROUP:IsTargetDetected(DCSObject) - -
    -
    - - - -

    Parameter

    -
      -
    • - -

      DCSObject :

      - -
    • -
    -
    -
    -
    -
    - GROUP:Message(Message, Duration) @@ -2522,343 +1511,6 @@ The duration of the message.

    - -GROUP:OptionROEHoldFire() - -
    -
    - -

    Holding weapons.

    - -

    Return value

    - -

    Group#GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROEHoldFirePossible() - -
    -
    - -

    Can the GROUP hold their weapons?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROEOpenFire() - -
    -
    - -

    Openfire.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROEOpenFirePossible() - -
    -
    - -

    Can the GROUP attack designated targets?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROEReturnFire() - -
    -
    - -

    Return fire.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROEReturnFirePossible() - -
    -
    - -

    Can the GROUP attack returning on enemy fire?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROEWeaponFree() - -
    -
    - -

    Weapon free.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROEWeaponFreePossible() - -
    -
    - -

    Can the GROUP attack targets of opportunity?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROTEvadeFire() - -
    -
    - -

    Evade on fire.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROTEvadeFirePossible() - -
    -
    - -

    Can the GROUP evade on enemy fire?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROTNoReaction() - -
    -
    - -

    No evasion on enemy threats.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROTNoReactionPossible() - -
    -
    - -

    Can the GROUP ignore enemy fire?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROTPassiveDefense() - -
    -
    - -

    Evasion passive defense.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROTPassiveDefensePossible() - -
    -
    - -

    Can the GROUP evade using passive defenses?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:OptionROTVertical() - -
    -
    - -

    Evade on fire using vertical manoeuvres.

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:OptionROTVerticalPossible() - -
    -
    - -

    Can the GROUP evade on fire using vertical manoeuvres?

    - -

    Return value

    - -

    #boolean:

    - - -
    -
    -
    -
    - - -GROUP:PopCurrentTask() - -
    -
    - -

    Popping current Task from the group.

    - -

    Return value

    - -

    Group#GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:PushTask(DCSTask, WaitTime) - -
    -
    - -

    Pushing Task on the queue from the group.

    - -

    Parameters

    -
      -
    • - -

      DCSTask :

      - -
    • -
    • - -

      WaitTime :

      - -
    • -
    -

    Return value

    - -

    Group#GROUP: -self

    - -
    -
    -
    -
    - GROUP:Register(GroupName) @@ -2902,1394 +1554,6 @@ self

    - -
    -
    -
    - - -GROUP:Route(GoPoints) - -
    -
    - -

    Make the group to follow a given route.

    - -

    Parameter

    -
      -
    • - -

      #table GoPoints : -A table of Route Points.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:RouteReturnToAirbase(ReturnAirbase, Speed) - -
    -
    - -

    (AIR) Return the Group to an Airbase#AIRBASE -A speed can be given in km/h.

    - - -

    A given formation can be given.

    - -

    Parameters

    - -

    Return value

    - -

    #string: -The route

    - -
    -
    -
    -
    - - -GROUP:SetCommand(DCSCommand) - -
    -
    - -

    Executes a command action

    - -

    Parameter

    - -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:SetTask(DCSTask, WaitTime) - -
    -
    - -

    Clearing the Task Queue and Setting the Task on the queue from the group.

    - -

    Parameters

    -
      -
    • - -

      DCSTask :

      - -
    • -
    • - -

      WaitTime :

      - -
    • -
    -

    Return value

    - -

    Group#GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskAttackGroup(AttackGroup, WeaponType, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit) - -
    -
    - -

    (AIR) Attack a Group.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP AttackGroup : -The Group to be attacked.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      DCSTypes#Distance Altitude : -(optional) Desired attack start altitude. Group/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/group will choose closest altitude to the desired attack start altitude. If the desired altitude is defined group/aircraft will not attack from safe altitude.

      - -
    • -
    • - -

      #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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskAttackMapObject(PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack) - -
    -
    - -

    (AIR) Attacking the map object (building, structure, e.t.c).

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 PointVec2 : -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.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      #boolean GroupAttack : -(optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskAttackUnit(AttackUnit, WeaponType, WeaponExpend, AttackQty, Direction, AttackQtyLimit, GroupAttack) - -
    -
    - -

    (AIR) Attack the Unit.

    - -

    Parameters

    -
      -
    • - -

      Unit#UNIT AttackUnit : -The unit.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      #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 "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.

      - -
    • -
    • - -

      #boolean GroupAttack : -(optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskBombing(PointVec2, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack) - -
    -
    - -

    (AIR) Delivering weapon at the point on the ground.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 PointVec2 : -2D-coordinates of the point to deliver weapon at.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      #boolean GroupAttack : -(optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskBombingRunway(Airbase, WeaponType, WeaponExpend, AttackQty, Direction, GroupAttack) - -
    -
    - -

    (AIR) Delivering weapon on the runway.

    - -

    Parameters

    -
      -
    • - -

      Airbase#AIRBASE Airbase : -Airbase to attack.

      - -
    • -
    • - -

      #number WeaponType : -(optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.WeaponExpend WeaponExpend : -(optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / group will choose expend on its own discretion.

      - -
    • -
    • - -

      #number AttackQty : -(optional) This parameter limits maximal quantity of attack. The aicraft/group will not make more attack than allowed even if the target group not destroyed and the aicraft/group still have ammo. If not defined the aircraft/group will attack target until it will be destroyed or until the aircraft/group will run out of ammo.

      - -
    • -
    • - -

      DCSTypes#Azimuth Direction : -(optional) Desired ingress direction from the target to the attacking aircraft. Group/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain group/aircraft will choose another direction.

      - -
    • -
    • - -

      #boolean GroupAttack : -(optional) Flag indicates that the target must be engaged by all aircrafts of the group. Has effect only if the task is assigned to a group, not to a single aircraft.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskCombo(DCSTasks) - -
    -
    - -

    Return a Combo Task taking an array of Tasks.

    - -

    Parameter

    - -

    Return value

    - -

    DCSTask#Task:

    - - -
    -
    -
    -
    - - -GROUP:TaskCondition(time, userFlag, userFlagValue, condition, duration, lastWayPoint) - -
    -
    - -

    Return a condition section for a controlled task.

    - -

    Parameters

    -
      -
    • - -

      DCSTime#Time time :

      - -
    • -
    • - -

      #string userFlag :

      - -
    • -
    • - -

      #boolean userFlagValue :

      - -
    • -
    • - -

      #string condition :

      - -
    • -
    • - -

      DCSTime#Time duration :

      - -
    • -
    • - -

      #number lastWayPoint : -return DCSTask#Task

      - -
    • -
    -
    -
    -
    -
    - - -GROUP:TaskControlled(DCSTask, DCSStopCondition) - -
    -
    - -

    Return a Controlled Task taking a Task and a TaskCondition.

    - -

    Parameters

    - -

    Return value

    - -

    DCSTask#Task:

    - - -
    -
    -
    -
    - - -GROUP:TaskEmbarkToTransport(Point, Radius) - -
    -
    - -

    Move to a defined Vec2 Point, and embark to a group when arrived within a defined Radius.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 Point : -The point where to wait.

      - -
    • -
    • - -

      #number Radius : -The radius of the embarking zone around the Point.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskEmbarking(Point, Duration, EmbarkingGroup) - -
    -
    - -

    (AIR) Move the group to a Vec2 Point, wait for a defined duration and embark a group.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 Point : -The point where to wait.

      - -
    • -
    • - -

      #number Duration : -The duration in seconds to wait.

      - -
    • -
    • - -

      #GROUP EmbarkingGroup : -The group to be embarked.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure

    - -
    -
    -
    -
    - - -GROUP:TaskEscort(EscortGroup, PointVec3, LastWaypointIndex, EngagementDistanceMax, TargetTypes, FollowGroup, EngagementDistance) - -
    -
    - -

    (AIR) Escort another airborne group.

    - - -

    The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. -The unit / group will also protect that group from threats of specified types.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP EscortGroup : -The group to be escorted.

      - -
    • -
    • - -

      DCSTypes#Vec3 PointVec3 : -Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around.

      - -
    • -
    • - -

      #number LastWaypointIndex : -Detach waypoint of another group. Once reached the unit / group Follow task is finished.

      - -
    • -
    • - -

      #number EngagementDistanceMax : -Maximal distance from escorted group to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax.

      - -
    • -
    • - -

      DCSTypes#AttributeNameArray TargetTypes : -Array of AttributeName that is contains threat categories allowed to engage.

      - -
    • -
    • - -

      FollowGroup :

      - -
    • -
    • - -

      EngagementDistance :

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskFAC_AttackGroup(AttackGroup, WeaponType, Designation, Datalink) - -
    -
    - -

    (AIR + GROUND) The task makes the group/unit a FAC and orders the FAC to control the target (enemy ground group) destruction.

    - - -

    The killer is player-controlled allied CAS-aircraft that is in contact with the FAC. -If the task is assigned to the group lead unit will be a FAC.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP AttackGroup : -Target GROUP.

      - -
    • -
    • - -

      #number WeaponType : -Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.

      - -
    • -
    • - -

      DCSTypes#AI.Task.Designation Designation : -(optional) Designation type.

      - -
    • -
    • - -

      #boolean Datalink : -(optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskFireAtPoint(PointVec2, Radius) - -
    -
    - -

    (GROUND) Fire at a VEC2 point until ammunition is finished.

    - -

    Parameters

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskFollow(FollowGroup, PointVec3, LastWaypointIndex) - -
    -
    - -

    (AIR) Following another airborne group.

    - - -

    The unit / group will follow lead unit of another group, wingmens of both groups will continue following their leaders. -If another group is on land the unit / group will orbit around.

    - -

    Parameters

    -
      -
    • - -

      Group#GROUP FollowGroup : -The group to be followed.

      - -
    • -
    • - -

      DCSTypes#Vec3 PointVec3 : -Position of the unit / lead unit of the group relative lead unit of another group in frame reference oriented by course of lead unit of another group. If another group is on land the unit / group will orbit around.

      - -
    • -
    • - -

      #number LastWaypointIndex : -Detach waypoint of another group. Once reached the unit / group Follow task is finished.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskFunction(WayPoint, WayPointIndex, FunctionString, FunctionArguments) - -
    -
    - - - -

    Parameters

    -
      -
    • - -

      WayPoint :

      - -
    • -
    • - -

      WayPointIndex :

      - -
    • -
    • - -

      FunctionString :

      - -
    • -
    • - -

      FunctionArguments :

      - -
    • -
    -
    -
    -
    -
    - - -GROUP:TaskHold() - -
    -
    - -

    (GROUND) Hold ground group from moving.

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskHoldPosition(Duration) - -
    -
    - -

    (AIR) Hold position at the current position of the first unit of the group.

    - -

    Parameter

    -
      -
    • - -

      #number Duration : -The maximum duration in seconds to hold the position.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskLandAtVec2(Point, Duration) - -
    -
    - -

    (AIR HELICOPTER) Landing at the ground.

    - - -

    For helicopters only.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 Point : -The point where to land.

      - -
    • -
    • - -

      #number Duration : -The duration in seconds to stay on the ground.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskLandAtZone(Zone, Duration, RandomPoint) - -
    -
    - -

    (AIR) Land the group at a @{Zone#ZONE_RADIUS).

    - -

    Parameters

    -
      -
    • - -

      Zone#ZONE Zone : -The zone where to land.

      - -
    • -
    • - -

      #number Duration : -The duration in seconds to stay on the ground.

      - -
    • -
    • - -

      RandomPoint :

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskMission(TaskMission) - -
    -
    - -

    (AIR + GROUND) Return a mission task from a mission template.

    - -

    Parameter

    -
      -
    • - -

      #table TaskMission : -A table containing the mission task.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task:

    - - -
    -
    -
    -
    - - -GROUP:TaskOrbitCircle(Altitude, Speed) - -
    -
    - -

    (AIR) Orbit at the current position of the first unit of the group at a specified alititude.

    - -

    Parameters

    -
      -
    • - -

      #number Altitude : -The altitude to hold the position.

      - -
    • -
    • - -

      #number Speed : -The speed flying when holding the position.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskOrbitCircleAtVec2(Point, Altitude, Speed) - -
    -
    - -

    (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec2 Point : -The point to hold the position.

      - -
    • -
    • - -

      #number Altitude : -The altitude to hold the position.

      - -
    • -
    • - -

      #number Speed : -The speed flying when holding the position.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskRefueling() - -
    -
    - -

    (AIR) Refueling from the nearest tanker.

    - - -

    No parameters.

    - -

    Return value

    - -

    DCSTask#Task: -The DCS task structure.

    - -
    -
    -
    -
    - - -GROUP:TaskRoute(Points) - -
    -
    - -

    Return a Misson task to follow a given route defined by Points.

    - -

    Parameter

    -
      -
    • - -

      #table Points : -A table of route points.

      - -
    • -
    -

    Return value

    - -

    DCSTask#Task:

    - - -
    -
    -
    -
    - - -GROUP:TaskRouteToVec2(Point, Speed) - -
    -
    - -

    (AIR + GROUND) Make the Group move to fly to a given point.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec3 Point : -The destination point in Vec3 format.

      - -
    • -
    • - -

      #number Speed : -The speed to travel.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskRouteToVec3(Point, Speed) - -
    -
    - -

    (AIR + GROUND) Make the Group move to a given point.

    - -

    Parameters

    -
      -
    • - -

      DCSTypes#Vec3 Point : -The destination point in Vec3 format.

      - -
    • -
    • - -

      #number Speed : -The speed to travel.

      - -
    • -
    -

    Return value

    - -

    #GROUP: -self

    - -
    -
    -
    -
    - - -GROUP:TaskRouteToZone(Zone, Randomize, Speed, Formation) - -
    -
    - -

    (AIR + GROUND) Route the group to a given zone.

    - - -

    The group final destination point can be randomized. -A speed can be given in km/h. -A given formation can be given.

    - -

    Parameters

    -
      -
    • - -

      Zone#ZONE Zone : -The zone where to route to.

      - -
    • -
    • - -

      #boolean Randomize : -Defines whether to target point gets randomized within the Zone.

      - -
    • -
    • - -

      #number Speed : -The speed.

      - -
    • -
    • - -

      Base#FORMATION Formation : -The formation string.

      - -
    • -
    -
    -
    -
    -
    - - -GROUP:TaskWrappedAction(DCSCommand, Index) - -
    -
    - -

    Return a WrappedAction Task taking a Command.

    - -

    Parameters

    - -

    Return value

    - -

    DCSTask#Task:

    - - -
    -
    -
    -
    - - -GROUP:WayPointExecute(WayPoint, WaitTime) - -
    -
    - -

    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 group will be 1!

    - -

    Parameters

    -
      -
    • - -

      #number WayPoint : -The WayPoint from where to execute the mission.

      - -
    • -
    • - -

      #number WaitTime : -The amount seconds to wait before initiating the mission.

      - -
    • -
    -

    Return value

    - -

    #GROUP:

    - - -
    -
    -
    -
    - - -GROUP:WayPointFunction(WayPoint, WayPointIndex, WayPointFunction, ...) - -
    -
    - -

    Registers a waypoint function that will be executed when the group moves over the WayPoint.

    - -

    Parameters

    -
      -
    • - -

      #number WayPoint : -The waypoint number. Note that the start waypoint on the route is WayPoint 1!

      - -
    • -
    • - -

      #number WayPointIndex : -When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions.

      - -
    • -
    • - -

      #function WayPointFunction : -The waypoint function to be called when the group moves over the waypoint. The waypoint function takes variable parameters.

      - -
    • -
    • - -

      ... :

      - -
    • -
    -

    Return value

    - -

    #GROUP:

    - - -
    -
    -
    -
    - - - -GROUP.WayPointFunctions - -
    -
    - - - -
    -
    -
    -
    - - -GROUP:WayPointInitialize(WayPoints) - -
    -
    - -

    Retrieve the group mission and allow to place function hooks within the mission waypoint plan.

    - - -

    Use the method Group#GROUP to define the hook functions for specific waypoints. - Use the method @{Group@GROUP:WayPointExecute) to start the execution of the new mission plan. - Note that when WayPointInitialize is called, the Mission of the group is RESTARTED!

    - -

    Parameter

    -
      -
    • - -

      #table WayPoints : -If WayPoints is given, then use the route.

      - -
    • -
    -

    Return value

    - -

    #GROUP:

    - - -
    -
    -
    -
    - - - -GROUP.WayPoints - -
    -
    - - - -
    -
    -
    -
    - - -GROUP:_GetController() - -
    -
    - -

    Get the controller for the GROUP.

    - -

    Return value

    - -

    DCSController#Controller:

    - -
    diff --git a/Moose Training/Documentation/Identifiable.html b/Moose Training/Documentation/Identifiable.html new file mode 100644 index 000000000..3b30e11ca --- /dev/null +++ b/Moose Training/Documentation/Identifiable.html @@ -0,0 +1,466 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module Identifiable

    + +

    This module contains the IDENTIFIABLE class.

    + + + +

    1) Identifiable#IDENTIFIABLE class, extends Object#OBJECT

    +

    The Identifiable#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:

    + + + +

    1.2) IDENTIFIABLE methods:

    +

    The following methods can be used to identify an identifiable object:

    + + + + +
    + + +

    Global(s)

    + + + + + +
    IDENTIFIABLE + +
    +

    Type IDENTIFIABLE

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    IDENTIFIABLE.ClassName + +
    IDENTIFIABLE:GetCategoryName() +

    Returns the DCS Identifiable category name as defined within the DCS Identifiable Descriptor.

    +
    IDENTIFIABLE:GetCoalition() +

    Returns coalition of the Identifiable.

    +
    IDENTIFIABLE:GetCountry() +

    Returns country of the Identifiable.

    +
    IDENTIFIABLE:GetDesc() +

    Returns Identifiable descriptor.

    +
    IDENTIFIABLE:GetName() +

    Returns DCS Identifiable object name.

    +
    IDENTIFIABLE:GetTypeName() +

    Returns the type name of the DCS Identifiable.

    +
    IDENTIFIABLE.IdentifiableName +

    The name of the identifiable.

    +
    IDENTIFIABLE:IsAlive() +

    Returns if the Identifiable is alive.

    +
    IDENTIFIABLE:New(IdentifiableName) +

    Create a new IDENTIFIABLE from a DCSIdentifiable

    +
    + +

    Global(s)

    +
    +
    + + #IDENTIFIABLE + +IDENTIFIABLE + +
    +
    + + + +
    +
    +

    Type Identifiable

    + +

    Type IDENTIFIABLE

    + +

    The IDENTIFIABLE class

    + +

    Field(s)

    +
    +
    + + #string + +IDENTIFIABLE.ClassName + +
    +
    + + + +
    +
    +
    +
    + + +IDENTIFIABLE:GetCategoryName() + +
    +
    + +

    Returns the DCS Identifiable category name as defined within the DCS Identifiable Descriptor.

    + +

    Return value

    + +

    #string: +The DCS Identifiable Category Name

    + +
    +
    +
    +
    + + +IDENTIFIABLE:GetCoalition() + +
    +
    + +

    Returns coalition of the Identifiable.

    + +

    Return values

    +
      +
    1. + +

      DCSCoalitionObject#coalition.side: +The side of the coalition.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +IDENTIFIABLE:GetCountry() + +
    +
    + +

    Returns country of the Identifiable.

    + +

    Return values

    +
      +
    1. + +

      DCScountry#country.id: +The country identifier.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +IDENTIFIABLE:GetDesc() + +
    +
    + +

    Returns Identifiable descriptor.

    + + +

    Descriptor type depends on Identifiable category.

    + +

    Return values

    +
      +
    1. + +

      DCSIdentifiable#Identifiable.Desc: +The Identifiable descriptor.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +IDENTIFIABLE:GetName() + +
    +
    + +

    Returns DCS Identifiable object name.

    + + +

    The function provides access to non-activated objects too.

    + +

    Return values

    +
      +
    1. + +

      #string: +The name of the DCS Identifiable.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +IDENTIFIABLE:GetTypeName() + +
    +
    + +

    Returns the type name of the DCS Identifiable.

    + +

    Return values

    +
      +
    1. + +

      #string: +The type name of the DCS Identifiable.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + #string + +IDENTIFIABLE.IdentifiableName + +
    +
    + +

    The name of the identifiable.

    + +
    +
    +
    +
    + + +IDENTIFIABLE:IsAlive() + +
    +
    + +

    Returns if the Identifiable is alive.

    + +

    Return values

    +
      +
    1. + +

      #boolean: +true if Identifiable is alive.

      + +
    2. +
    3. + +

      #nil: +The DCS Identifiable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +IDENTIFIABLE:New(IdentifiableName) + +
    +
    + +

    Create a new IDENTIFIABLE from a DCSIdentifiable

    + +

    Parameter

    + +

    Return value

    + +

    #IDENTIFIABLE: +self

    + +
    +
    + +
    + +
    + + diff --git a/Moose Training/Documentation/MISSION.html b/Moose Training/Documentation/MISSION.html index 83f2d4e69..a44aece40 100644 --- a/Moose Training/Documentation/MISSION.html +++ b/Moose Training/Documentation/MISSION.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/MOVEMENT.html b/Moose Training/Documentation/MOVEMENT.html index 578915315..305f917a3 100644 --- a/Moose Training/Documentation/MOVEMENT.html +++ b/Moose Training/Documentation/MOVEMENT.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Menu.html b/Moose Training/Documentation/Menu.html index 9b6cf848b..0f175ce8f 100644 --- a/Moose Training/Documentation/Menu.html +++ b/Moose Training/Documentation/Menu.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Message.html b/Moose Training/Documentation/Message.html index 85a2767a2..238b511e6 100644 --- a/Moose Training/Documentation/Message.html +++ b/Moose Training/Documentation/Message.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/MissileTrainer.html b/Moose Training/Documentation/MissileTrainer.html index db9d7acc5..e387d6ad0 100644 --- a/Moose Training/Documentation/MissileTrainer.html +++ b/Moose Training/Documentation/MissileTrainer.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/NOTASK.html b/Moose Training/Documentation/NOTASK.html index 5d097b91e..d295f2fd7 100644 --- a/Moose Training/Documentation/NOTASK.html +++ b/Moose Training/Documentation/NOTASK.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Object.html b/Moose Training/Documentation/Object.html new file mode 100644 index 000000000..eb36a3165 --- /dev/null +++ b/Moose Training/Documentation/Object.html @@ -0,0 +1,523 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module Object

    + +

    This module contains the OBJECT class.

    + + + +

    1) Object#OBJECT class, extends Base#BASE

    +

    The 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:

    + + + +

    1.2) OBJECT methods:

    +

    The following methods can be used to identify an Object object:

    + + + +
    + + +

    Global(s)

    + + + + + +
    OBJECT + +
    +

    Type DCSObject

    + + + + + +
    DCSObject.id_ +

    The ID of the controllable in DCS

    +
    + +

    Type OBJECT

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OBJECT.ClassName + +
    OBJECT:GetCallSign() +

    Returns the Object's callsign - the localized string.

    +
    OBJECT:GetCategoryName() +

    Returns the DCS Object category name as defined within the DCS Object Descriptor.

    +
    OBJECT:GetCoalition() +

    Returns coalition of the Object.

    +
    OBJECT:GetCountry() +

    Returns country of the Object.

    +
    OBJECT:GetDesc() +

    Returns Object descriptor.

    +
    OBJECT:GetName() +

    Returns DCS Object object name.

    +
    OBJECT:GetTypeName() +

    Returns the type name of the DCS Object.

    +
    OBJECT:IsAlive() +

    Returns if the Object is alive.

    +
    OBJECT:New(ObjectName) +

    Create a new OBJECT from a DCSObject

    +
    OBJECT.ObjectName +

    The name of the Object.

    +
    + +

    Global(s)

    +
    +
    + + #OBJECT + +OBJECT + +
    +
    + + + +
    +
    +

    Type Object

    + +

    Type DCSObject

    + +

    A DCSObject

    + +

    Field(s)

    +
    +
    + + +DCSObject.id_ + +
    +
    + +

    The ID of the controllable in DCS

    + +
    +
    + +

    Type OBJECT

    + +

    The OBJECT class

    + +

    Field(s)

    +
    +
    + + #string + +OBJECT.ClassName + +
    +
    + + + +
    +
    +
    +
    + + +OBJECT:GetCallSign() + +
    +
    + +

    Returns the Object's callsign - the localized string.

    + +

    Return values

    +
      +
    1. + +

      #string: +The Callsign of the Object.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:GetCategoryName() + +
    +
    + +

    Returns the DCS Object category name as defined within the DCS Object Descriptor.

    + +

    Return value

    + +

    #string: +The DCS Object Category Name

    + +
    +
    +
    +
    + + +OBJECT:GetCoalition() + +
    +
    + +

    Returns coalition of the Object.

    + +

    Return values

    +
      +
    1. + +

      DCSCoalitionObject#coalition.side: +The side of the coalition.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:GetCountry() + +
    +
    + +

    Returns country of the Object.

    + +

    Return values

    +
      +
    1. + +

      DCScountry#country.id: +The country identifier.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:GetDesc() + +
    +
    + +

    Returns Object descriptor.

    + + +

    Descriptor type depends on Object category.

    + +

    Return values

    +
      +
    1. + +

      DCSObject#Object.Desc: +The Object descriptor.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:GetName() + +
    +
    + +

    Returns DCS Object object name.

    + + +

    The function provides access to non-activated objects too.

    + +

    Return values

    +
      +
    1. + +

      #string: +The name of the DCS Object.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:GetTypeName() + +
    +
    + +

    Returns the type name of the DCS Object.

    + +

    Return values

    +
      +
    1. + +

      #string: +The type name of the DCS Object.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:IsAlive() + +
    +
    + +

    Returns if the Object is alive.

    + +

    Return values

    +
      +
    1. + +

      #boolean: +true if Object is alive.

      + +
    2. +
    3. + +

      #nil: +The DCS Object is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +OBJECT:New(ObjectName) + +
    +
    + +

    Create a new OBJECT from a DCSObject

    + +

    Parameter

    + +

    Return value

    + +

    #OBJECT: +self

    + +
    +
    +
    +
    + + #string + +OBJECT.ObjectName + +
    +
    + +

    The name of the Object.

    + +
    +
    + +
    + +
    + + diff --git a/Moose Training/Documentation/PICKUPTASK.html b/Moose Training/Documentation/PICKUPTASK.html index f996c7e6b..b4d42b424 100644 --- a/Moose Training/Documentation/PICKUPTASK.html +++ b/Moose Training/Documentation/PICKUPTASK.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/PatrolZone.html b/Moose Training/Documentation/PatrolZone.html index 66df2c4af..57e301d3f 100644 --- a/Moose Training/Documentation/PatrolZone.html +++ b/Moose Training/Documentation/PatrolZone.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Point.html b/Moose Training/Documentation/Point.html index f1202e5d5..ad61c002b 100644 --- a/Moose Training/Documentation/Point.html +++ b/Moose Training/Documentation/Point.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Positionable.html b/Moose Training/Documentation/Positionable.html new file mode 100644 index 000000000..d6801e50e --- /dev/null +++ b/Moose Training/Documentation/Positionable.html @@ -0,0 +1,518 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module Positionable

    + +

    This module contains the POSITIONABLE class.

    + + + +

    1) Positionable#POSITIONABLE class, extends Identifiable#IDENTIFIABLE

    +

    The Positionable#POSITIONABLE class is a wrapper class to handle the DCS Positionable objects:

    + +
      +
    • Support all DCS Positionable APIs.
    • +
    • Enhance with Positionable specific APIs not in the DCS Positionable API set.
    • +
    • Manage the "state" of the DCS Positionable.
    • +
    + +

    1.1) POSITIONABLE constructor:

    +

    The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance:

    + + + +

    1.2) POSITIONABLE methods:

    +

    The following methods can be used to identify an measurable object:

    + + + +
    + + +

    Global(s)

    + + + + + +
    POSITIONABLE + +
    +

    Type DCSPositionable

    + + + + + +
    DCSPositionable.id_ +

    The ID of the controllable in DCS

    +
    + +

    Type POSITIONABLE

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    POSITIONABLE.ClassName + +
    POSITIONABLE:GetAltitude() +

    Returns the altitude of the DCS Positionable.

    +
    POSITIONABLE:GetHeading() +

    Returns the DCS Positionable heading.

    +
    POSITIONABLE:GetPointVec2() +

    Returns the DCSTypes#Vec2 vector indicating the point in 2D of the DCS Positionable within the mission.

    +
    POSITIONABLE:GetPointVec3() +

    Returns the DCSTypes#Vec3 vector indicating the point in 3D of the DCS Positionable within the mission.

    +
    POSITIONABLE:GetPositionVec3() +

    Returns the DCSTypes#Position3 position vectors indicating the point and direction vectors in 3D of the DCS Positionable within the mission.

    +
    POSITIONABLE:GetVelocity() +

    Returns the DCS Positionable velocity vector.

    +
    POSITIONABLE:InAir() +

    Returns true if the DCS Positionable is in the air.

    +
    POSITIONABLE:IsAboveRunway() +

    Returns if the Positionable is located above a runway.

    +
    POSITIONABLE:New(PositionableName) +

    Create a new POSITIONABLE from a DCSPositionable

    +
    POSITIONABLE.PositionableName +

    The name of the measurable.

    +
    + +

    Global(s)

    +
    +
    + + #POSITIONABLE + +POSITIONABLE + +
    +
    + + + +
    +
    +

    Type Positionable

    + +

    Type DCSPositionable

    + +

    A DCSPositionable

    + +

    Field(s)

    +
    +
    + + +DCSPositionable.id_ + +
    +
    + +

    The ID of the controllable in DCS

    + +
    +
    + +

    Type POSITIONABLE

    + +

    The POSITIONABLE class

    + +

    Field(s)

    +
    +
    + + #string + +POSITIONABLE.ClassName + +
    +
    + + + +
    +
    +
    +
    + + +POSITIONABLE:GetAltitude() + +
    +
    + +

    Returns the altitude of the DCS Positionable.

    + +

    Return values

    +
      +
    1. + +

      DCSTypes#Distance: +The altitude of the DCS Positionable.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:GetHeading() + +
    +
    + +

    Returns the DCS Positionable heading.

    + +

    Return value

    + +

    #number: +The DCS Positionable heading

    + +
    +
    +
    +
    + + +POSITIONABLE:GetPointVec2() + +
    +
    + +

    Returns the DCSTypes#Vec2 vector indicating the point in 2D of the DCS Positionable within the mission.

    + +

    Return values

    +
      +
    1. + +

      DCSTypes#Vec2: +The 2D point vector of the DCS Positionable.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:GetPointVec3() + +
    +
    + +

    Returns the DCSTypes#Vec3 vector indicating the point in 3D of the DCS Positionable within the mission.

    + +

    Return values

    +
      +
    1. + +

      DCSTypes#Vec3: +The 3D point vector of the DCS Positionable.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:GetPositionVec3() + +
    +
    + +

    Returns the DCSTypes#Position3 position vectors indicating the point and direction vectors in 3D of the DCS Positionable within the mission.

    + +

    Return values

    +
      +
    1. + +

      DCSTypes#Position: +The 3D position vectors of the DCS Positionable.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:GetVelocity() + +
    +
    + +

    Returns the DCS Positionable velocity vector.

    + +

    Return values

    +
      +
    1. + +

      DCSTypes#Vec3: +The velocity vector

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:InAir() + +
    +
    + +

    Returns true if the DCS Positionable is in the air.

    + +

    Return values

    +
      +
    1. + +

      #boolean: +true if in the air.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:IsAboveRunway() + +
    +
    + +

    Returns if the Positionable is located above a runway.

    + +

    Return values

    +
      +
    1. + +

      #boolean: +true if Positionable is above a runway.

      + +
    2. +
    3. + +

      #nil: +The DCS Positionable is not existing or alive.

      + +
    4. +
    +
    +
    +
    +
    + + +POSITIONABLE:New(PositionableName) + +
    +
    + +

    Create a new POSITIONABLE from a DCSPositionable

    + +

    Parameter

    + +

    Return value

    + +

    #POSITIONABLE: +self

    + +
    +
    +
    +
    + + #string + +POSITIONABLE.PositionableName + +
    +
    + +

    The name of the measurable.

    + +
    +
    + +
    + +
    + + diff --git a/Moose Training/Documentation/ROUTETASK.html b/Moose Training/Documentation/ROUTETASK.html index d09a08b26..b4b6af4de 100644 --- a/Moose Training/Documentation/ROUTETASK.html +++ b/Moose Training/Documentation/ROUTETASK.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/STAGE.html b/Moose Training/Documentation/STAGE.html index e36f92952..bb3a81b5d 100644 --- a/Moose Training/Documentation/STAGE.html +++ b/Moose Training/Documentation/STAGE.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Scheduler.html b/Moose Training/Documentation/Scheduler.html index 785c3ba4d..0e09087bb 100644 --- a/Moose Training/Documentation/Scheduler.html +++ b/Moose Training/Documentation/Scheduler.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Scoring.html b/Moose Training/Documentation/Scoring.html index 9c7a0404a..fd4e0d8a4 100644 --- a/Moose Training/Documentation/Scoring.html +++ b/Moose Training/Documentation/Scoring.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Sead.html b/Moose Training/Documentation/Sead.html index 0499fd234..d712387fc 100644 --- a/Moose Training/Documentation/Sead.html +++ b/Moose Training/Documentation/Sead.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Set.html b/Moose Training/Documentation/Set.html index 597140810..c618696b0 100644 --- a/Moose Training/Documentation/Set.html +++ b/Moose Training/Documentation/Set.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • @@ -485,6 +491,12 @@ The following iterator methods are currently available within the SETAIRBAS SET_BASE:ForEach(IteratorFunction, arg, Set, Function, FunctionArguments)

    Iterate the SETBASE and derived classes and call an iterator function for the given SETBASE, providing the Object for each element within the set and optional parameters.

    + + + + SET_BASE:GetSet() + +

    Gets the Set.

    @@ -803,6 +815,12 @@ The following iterator methods are currently available within the SETAIRBAS SET_UNIT:AddInDatabase(Event)

    Handles the Database to check on an event (birth) that the Object was added in the Database.

    + + + + SET_UNIT:AddUnit(AddUnit) + +

    Add UNIT(s) to SET_UNIT.

    @@ -1547,6 +1565,24 @@ self

    + +SET_BASE:GetSet() + +
    +
    + +

    Gets the Set.

    + +

    Return value

    + +

    #SET_BASE: +self

    + +
    +
    +
    +
    + SET_BASE:IsIncludeObject(Object) @@ -2912,6 +2948,33 @@ The UNIT

    + +SET_UNIT:AddUnit(AddUnit) + +
    +
    + +

    Add UNIT(s) to SET_UNIT.

    + +

    Parameter

    +
      +
    • + +

      #string AddUnit : +A single UNIT.

      + +
    • +
    +

    Return value

    + +

    #SET_UNIT: +self

    + +
    +
    +
    +
    + SET_UNIT:AddUnitsByName(AddUnitNames) @@ -2931,8 +2994,8 @@ A single name or an array of UNIT names.

    Return value

    - -

    self

    +

    #SET_UNIT: +self

    diff --git a/Moose Training/Documentation/Spawn.html b/Moose Training/Documentation/Spawn.html index 6b4e369eb..f50b51d79 100644 --- a/Moose Training/Documentation/Spawn.html +++ b/Moose Training/Documentation/Spawn.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Static.html b/Moose Training/Documentation/Static.html index 95cc3cc4c..70c8ae9ed 100644 --- a/Moose Training/Documentation/Static.html +++ b/Moose Training/Documentation/Static.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • @@ -78,7 +84,7 @@ -

    1) Static#STATIC class, extends Unit#UNIT

    +

    1) Static#STATIC class, extends 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 Static#STATIC class is a wrapper class to handle the DCS Static objects:

    diff --git a/Moose Training/Documentation/StaticObject.html b/Moose Training/Documentation/StaticObject.html index 54ac84727..a7273b25a 100644 --- a/Moose Training/Documentation/StaticObject.html +++ b/Moose Training/Documentation/StaticObject.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/TASK.html b/Moose Training/Documentation/TASK.html index 49736f3e0..8c57f3460 100644 --- a/Moose Training/Documentation/TASK.html +++ b/Moose Training/Documentation/TASK.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • diff --git a/Moose Training/Documentation/Unit.html b/Moose Training/Documentation/Unit.html index 77eadcbf0..573d22500 100644 --- a/Moose Training/Documentation/Unit.html +++ b/Moose Training/Documentation/Unit.html @@ -24,6 +24,7 @@
  • CARGO
  • CleanUp
  • Client
  • +
  • Controllable
  • DCSAirbase
  • DCSCoalitionObject
  • DCSCommand
  • @@ -41,19 +42,24 @@
  • DESTROYRADARSTASK
  • DESTROYUNITTYPESTASK
  • Database
  • +
  • Detection
  • Escort
  • Event
  • +
  • Fac
  • GOHOMETASK
  • Group
  • +
  • Identifiable
  • MOVEMENT
  • Menu
  • Message
  • MissileTrainer
  • Mission
  • NOTASK
  • +
  • Object
  • PICKUPTASK
  • PatrolZone
  • Point
  • +
  • Positionable
  • ROUTETASK
  • STAGE
  • Scheduler
  • @@ -78,7 +84,7 @@ -

    1) Unit#UNIT class, extends Base#BASE

    +

    1) Unit#UNIT class, extends Controllable#CONTROLLABLE

    The Unit#UNIT class is a wrapper class to handle the DCS Unit objects: