From 303b3a0efea72b8643a7b3bd2ef43c75f6361e42 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 26 Apr 2017 09:59:10 +0200 Subject: [PATCH 01/32] First version --- Moose Development/Moose/AI/AI_Bomb.lua | 598 +++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100644 Moose Development/Moose/AI/AI_Bomb.lua diff --git a/Moose Development/Moose/AI/AI_Bomb.lua b/Moose Development/Moose/AI/AI_Bomb.lua new file mode 100644 index 000000000..406874ed1 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Bomb.lua @@ -0,0 +1,598 @@ +--- **AI** -- **Provide Close Air Support to friendly ground troops.** +-- +-- ![Banner Image](..\Presentations\AI_BOMB\Dia1.JPG) +-- +-- === +-- +-- AI_BOMB classes makes AI Controllables execute bombing tasks. +-- +-- There are the following types of BOMB classes defined: +-- +-- * @{#AI_BOMB_ZONE}: Perform a BOMB in a zone. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [AI_BOMB Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support) +-- +-- ### [AI_BOMB Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [AI_BOMB YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2) +-- +-- === +-- +-- # **API CHANGE HISTORY** +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2017-01-15: Initial class and API. +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision. +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module AI_Cas + + +--- AI_BOMB_ZONE class +-- @type AI_BOMB_ZONE +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. +-- @extends AI.AI_Patrol#AI_PATROL_ZONE + +--- # AI_BOMB_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE} +-- +-- AI_BOMB_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +-- +-- The AI_BOMB_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. +-- The AI_BOMB_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. +-- +-- ![HoldAndEngage](..\Presentations\AI_BOMB\Dia3.JPG) +-- +-- The AI_BOMB_ZONE is assigned a @{Group} and this must be done before the AI_BOMB_ZONE process can be started through the **Start** event. +-- +-- ![Start Event](..\Presentations\AI_BOMB\Dia4.JPG) +-- +-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone, +-- using a random speed within the given altitude and speed limits. +-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. +-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. +-- +-- ![Route Event](..\Presentations\AI_BOMB\Dia5.JPG) +-- +-- When the AI is commanded to provide Close Air Support (through the event **Engage**), the AI will fly towards the Engage Zone. +-- Any target that is detected in the Engage Zone will be reported and will be destroyed by the AI. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia6.JPG) +-- +-- The AI will detect the targets and will only destroy the targets within the Engage Zone. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia7.JPG) +-- +-- Every target that is destroyed, is reported< by the AI. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia8.JPG) +-- +-- Note that the AI does not know when the Engage Zone is cleared, and therefore will keep circling in the zone. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia9.JPG) +-- +-- Until it is notified through the event **Accomplish**, which is to be triggered by an observing party: +-- +-- * a FAC +-- * a timed event +-- * a menu option selected by a human +-- * a condition +-- * others ... +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia10.JPG) +-- +-- When the AI has accomplished the BOMB, it will fly back to the Patrol Zone. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia11.JPG) +-- +-- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone. +-- It can be notified to go RTB through the **RTB** event. +-- +-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. +-- +-- ![Engage Event](..\Presentations\AI_BOMB\Dia12.JPG) +-- +-- # 1. AI_BOMB_ZONE constructor +-- +-- * @{#AI_BOMB_ZONE.New}(): Creates a new AI_BOMB_ZONE object. +-- +-- ## 2. AI_BOMB_ZONE is a FSM +-- +-- ![Process](..\Presentations\AI_BOMB\Dia2.JPG) +-- +-- ### 2.1. AI_BOMB_ZONE States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Engaging** ( Group ): The AI is engaging the targets in the Engage Zone, executing BOMB. +-- * **Returning** ( Group ): The AI is returning to Base.. +-- +-- ### 2.2. AI_BOMB_ZONE Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_BOMB_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds. +-- * **@{#AI_BOMB_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_BOMB_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. +-- * **@{#AI_BOMB_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task. +-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- === +-- +-- @field #AI_BOMB_ZONE +AI_BOMB_ZONE = { + ClassName = "AI_BOMB_ZONE", +} + + + +--- Creates a new AI_BOMB_ZONE object +-- @param #AI_BOMB_ZONE self +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_BOMB_ZONE self +function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_BOMB_ZONE + + self.EngageZone = EngageZone + self.Accomplished = false + + self:SetDetectionZone( self.EngageZone ) + + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_BOMB_ZONE] OnBeforeEngage + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Engage. + -- @function [parent=#AI_BOMB_ZONE] OnAfterEngage + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Engage. + -- @function [parent=#AI_BOMB_ZONE] Engage + -- @param #AI_BOMB_ZONE self + -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. + -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (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. + -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. + -- @param Dcs.DCSTypes#Azimuth EngageDirection (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. + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_BOMB_ZONE] __Engage + -- @param #AI_BOMB_ZONE self + -- @param #number Delay The delay in seconds. + -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. + -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. + -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (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. + -- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack. + -- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. + -- @param Dcs.DCSTypes#Azimuth EngageDirection (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. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_BOMB_ZONE] OnLeaveEngaging +-- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @return #boolean Return false to cancel Transition. + +--- OnEnter Transition Handler for State Engaging. +-- @function [parent=#AI_BOMB_ZONE] OnEnterEngaging +-- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. + + self:AddTransition( "Engaging", "Target", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_BOMB_ZONE] OnBeforeFired + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Fired. + -- @function [parent=#AI_BOMB_ZONE] OnAfterFired + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Fired. + -- @function [parent=#AI_BOMB_ZONE] Fired + -- @param #AI_BOMB_ZONE self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_BOMB_ZONE] __Fired + -- @param #AI_BOMB_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_BOMB_ZONE] OnBeforeDestroy + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Destroy. + -- @function [parent=#AI_BOMB_ZONE] OnAfterDestroy + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_BOMB_ZONE] Destroy + -- @param #AI_BOMB_ZONE self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_BOMB_ZONE] __Destroy + -- @param #AI_BOMB_ZONE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_BOMB_ZONE] OnBeforeAbort + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Abort. + -- @function [parent=#AI_BOMB_ZONE] OnAfterAbort + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Abort. + -- @function [parent=#AI_BOMB_ZONE] Abort + -- @param #AI_BOMB_ZONE self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_BOMB_ZONE] __Abort + -- @param #AI_BOMB_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_BOMB_ZONE] OnBeforeAccomplish + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @return #boolean Return false to cancel Transition. + + --- OnAfter Transition Handler for Event Accomplish. + -- @function [parent=#AI_BOMB_ZONE] OnAfterAccomplish + -- @param #AI_BOMB_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + + --- Synchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_BOMB_ZONE] Accomplish + -- @param #AI_BOMB_ZONE self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_BOMB_ZONE] __Accomplish + -- @param #AI_BOMB_ZONE self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- Set the Engage Zone where the AI is performing BOMB. Note that if the EngageZone is changed, the AI needs to re-detect targets. +-- @param #AI_BOMB_ZONE self +-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing BOMB. +-- @return #AI_BOMB_ZONE self +function AI_BOMB_ZONE:SetEngageZone( EngageZone ) + self:F2() + + if EngageZone then + self.EngageZone = EngageZone + else + self.EngageZone = nil + end +end + + + +--- onafter State Transition for Event Start. +-- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_BOMB_ZONE:onafterStart( Controllable, From, Event, To ) + + -- Call the parent Start event handler + self:GetParent(self).onafterStart( self, Controllable, From, Event, To ) + self:HandleEvent( EVENTS.Dead ) + + self:SetDetectionDeactivated() -- When not engaging, set the detection off. +end + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +function _NewEngageRoute( AIControllable ) + + AIControllable:T( "NewEngageRoute" ) + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_BOMB_ZONE + EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection ) +end + + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_BOMB_ZONE:onbeforeEngage( Controllable, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_BOMB_ZONE:onafterTarget( Controllable, From, Event, To ) + self:E("onafterTarget") + + if Controllable:IsAlive() then + + local AttackTasks = {} + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + if DetectedUnit:IsAlive() then + if DetectedUnit:IsInZone( self.EngageZone ) then + if Detected == true then + self:E( {"Target: ", DetectedUnit } ) + self.DetectedUnits[DetectedUnit] = false + local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil ) + self.Controllable:PushTask( AttackTask, 1 ) + end + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + self:__Target( -10 ) + + end +end + + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_BOMB_ZONE:onafterAbort( Controllable, From, Event, To ) + Controllable:ClearTasks() + self:__Route( 1 ) +end + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. +-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. +-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (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 EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. +-- @param Dcs.DCSTypes#Azimuth EngageDirection (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. +function AI_BOMB_ZONE:onafterEngage( Controllable, From, Event, To, + EngageSpeed, + EngageAltitude, + EngageWeaponExpend, + EngageAttackQty, + EngageDirection ) + self:F("onafterEngage") + + self.EngageSpeed = EngageSpeed or 400 + self.EngageAltitude = EngageAltitude or 2000 + self.EngageWeaponExpend = EngageWeaponExpend + self.EngageAttackQty = EngageAttackQty + self.EngageDirection = EngageDirection + + if Controllable:IsAlive() then + + local EngageRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToEngageZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + self.EngageSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = CurrentRoutePoint + + local AttackTasks = {} + + for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( DetectedUnit ) + if DetectedUnit:IsAlive() then + if DetectedUnit:IsInZone( self.EngageZone ) then + self:E( {"Engaging ", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit, + true, + EngageWeaponExpend, + EngageAttackQty, + EngageDirection + ) + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) + + --- Define a random point in the @{Zone}. The AI will fly to that point within the zone. + + --- Find a random 2D point in EngageZone. + local ToTargetVec2 = self.EngageZone:GetRandomVec2() + self:T2( ToTargetVec2 ) + + --- Obtain a 3D @{Point} from the 2D point + altitude. + local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y ) + + --- Create a route point of type air. + local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + self.EngageSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = ToTargetRoutePoint + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + Controllable:WayPointInitialize( EngageRoute ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + Controllable:SetState( Controllable, "EngageZone", self ) + + Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" ) + + --- NOW ROUTE THE GROUP! + Controllable:WayPointExecute( 1 ) + + Controllable:OptionROEOpenFire() + Controllable:OptionROTVertical() + + self:SetDetectionInterval( 2 ) + self:SetDetectionActivated() + self:__Target( -2 ) -- Start Targetting + end +end + + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +function AI_BOMB_ZONE:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self:SetDetectionDeactivated() +end + + +--- @param #AI_BOMB_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. +-- @param #string From The From State string. +-- @param #string Event The Event string. +-- @param #string To The To State string. +-- @param Core.Event#EVENTDATA EventData +function AI_BOMB_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) + + if EventData.IniUnit then + self.DetectedUnits[EventData.IniUnit] = nil + end +end + + +--- @param #AI_BOMB_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_BOMB_ZONE:OnEventDead( EventData ) + self:F( { "EventDead", EventData } ) + + if EventData.IniDCSUnit then + if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit] then + self:__Destroy( 1, EventData ) + end + end +end + + From 625450ba127936ec64cbe8c1ebafbaaaf45c6fbe Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 5 May 2017 13:37:04 +0200 Subject: [PATCH 02/32] Event prefix can be nil, if the event occurs on a non-spawned group with no # tag. --- Moose Development/Moose/Functional/Spawn.lua | 78 +++++++++++--------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index c6faf2ee8..6e9386a7d 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -1595,11 +1595,13 @@ function SPAWN:_OnBirth( EventData ) if SpawnGroup then local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) - self:T( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits + 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end + if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! + self:T( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self.AliveUnits = self.AliveUnits + 1 + self:T( "Alive Units: " .. self.AliveUnits ) + end + end end end @@ -1616,11 +1618,13 @@ function SPAWN:_OnDeadOrCrash( EventData ) if SpawnGroup then local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) - self:T( { "Dead event: " .. EventPrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self.AliveUnits = self.AliveUnits - 1 - self:T( "Alive Units: " .. self.AliveUnits ) - end + if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! + self:T( { "Dead event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self.AliveUnits = self.AliveUnits - 1 + self:T( "Alive Units: " .. self.AliveUnits ) + end + end end end @@ -1634,10 +1638,12 @@ function SPAWN:_OnTakeOff( EventData ) local SpawnGroup = EventData.IniGroup if SpawnGroup then local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) - self:T( { "TakeOff event: " .. EventPrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - self:T( "self.Landed = false" ) - SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false ) + if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! + self:T( { "TakeOff event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + self:T( "self.Landed = false" ) + SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false ) + end end end end @@ -1652,16 +1658,18 @@ function SPAWN:_OnLand( EventData ) local SpawnGroup = EventData.IniGroup if SpawnGroup then local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) - self:T( { "Land event: " .. EventPrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - -- TODO: Check if this is the last unit of the group that lands. - SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true ) - if self.RepeatOnLanding then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end + if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! + self:T( { "Land event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + -- TODO: Check if this is the last unit of the group that lands. + SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true ) + if self.RepeatOnLanding then + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) + self:T( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) + self:ReSpawn( SpawnGroupIndex ) + end + end + end end end @@ -1676,16 +1684,18 @@ function SPAWN:_OnEngineShutDown( EventData ) local SpawnGroup = EventData.IniGroup if SpawnGroup then local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) - self:T( { "EngineShutdown event: " .. EventPrefix } ) - if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then - -- todo: test if on the runway - local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" ) - if Landed and self.RepeatOnEngineShutDown then - local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) - self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) - self:ReSpawn( SpawnGroupIndex ) - end - end + if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! + self:T( { "EngineShutdown event: " .. EventPrefix } ) + if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then + -- todo: test if on the runway + local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" ) + if Landed and self.RepeatOnEngineShutDown then + local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) + self:T( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) + self:ReSpawn( SpawnGroupIndex ) + end + end + end end end From dac4c48850ef833239ec5c9e596dc428031c76e7 Mon Sep 17 00:00:00 2001 From: entropySG Date: Fri, 5 May 2017 14:32:56 +0200 Subject: [PATCH 03/32] Fix Missile Distance Message in Missile Trainer Menu --- Moose Development/Moose/Functional/MissileTrainer.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index 511cbca44..38b2008ae 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -442,7 +442,7 @@ function MISSILETRAINER._MenuMessages( MenuParameters ) if MenuParameters.Distance ~= nil then self.Distance = MenuParameters.Distance - MESSAGE:New( "Hit detection distance set to " .. self.Distance .. " meters", 15, "Menu" ):ToAll() + MESSAGE:New( "Hit detection distance set to " .. self.Distance * 1000 .. " meters", 15, "Menu" ):ToAll() end end From 9a5446216424fc7fa3b3275c91d54b7176797121 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 5 May 2017 14:37:55 +0200 Subject: [PATCH 04/32] Fixed problem upon mission success. --- Moose Development/Moose/Tasking/Task.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 15c88a013..f30c338fe 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -585,7 +585,9 @@ function TASK:UnAssignFromGroups() self:F2() for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do - self:UnAssignFromGroup( TaskGroup ) + if self:IsGroupAssigned(TaskGroup) then + self:UnAssignFromGroup( TaskGroup ) + end end end From cb7ba702ffa0f6d2b376b845541c7e1f80d2551d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 5 May 2017 15:50:21 +0200 Subject: [PATCH 05/32] Correct handling of crashing player when assigned to a task --- .../Moose/Tasking/CommandCenter.lua | 5 ++- Moose Development/Moose/Tasking/Mission.lua | 12 +++--- Moose Development/Moose/Tasking/Task.lua | 42 ++++++++++++------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 2a696ead2..248f5fd00 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -189,7 +189,10 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) function( self, EventData ) local PlayerUnit = EventData.IniUnit for MissionID, Mission in pairs( self:GetMissions() ) do - Mission:CrashUnit( PlayerUnit ) + local Mission = Mission -- Tasking.Mission#MISSION + if Mission:IsENGAGED() then + Mission:CrashUnit( PlayerUnit ) + end end end ) diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index c19af3f75..751768130 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -308,19 +308,17 @@ end -- If the Unit is part of a Task in the Mission, true is returned. -- @param #MISSION self -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player crashing. --- @return #boolean true if Unit is part of a Task in the Mission. +-- @return #MISSION function MISSION:CrashUnit( PlayerUnit ) self:F( { PlayerUnit = PlayerUnit } ) - local PlayerUnitRemoved = false - for TaskID, Task in pairs( self:GetTasks() ) do - if Task:CrashUnit( PlayerUnit ) then - PlayerUnitRemoved = true - end + local Task = Task -- Tasking.Task#TASK + local PlayerGroup = PlayerUnit:GetGroup() + Task:CrashGroup( PlayerGroup ) end - return PlayerUnitRemoved + return self end --- Add a scoring to the mission. diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index f30c338fe..cf306bfee 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -260,7 +260,7 @@ end -- If the Unit is part of the Task, true is returned. -- @param #TASK self -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. +-- @return #TASK function TASK:AbortGroup( PlayerGroup ) self:F( { PlayerGroup = PlayerGroup } ) @@ -312,14 +312,11 @@ end -- If the Unit is part of the Task, true is returned. -- @param #TASK self -- @param Wrapper.Unit#UNIT PlayerUnit The CLIENT or UNIT of the Player aborting the Task. --- @return #boolean true if Unit is part of the Task. -function TASK:CrashUnit( PlayerUnit ) - self:F( { PlayerUnit = PlayerUnit } ) - - local PlayerUnitCrashed = false +-- @return #TASK +function TASK:CrashGroup( PlayerGroup ) + self:F( { PlayerGroup = PlayerGroup } ) local PlayerGroups = self:GetGroups() - local PlayerGroup = PlayerUnit:GetGroup() -- Is the PlayerGroup part of the PlayerGroups? if PlayerGroups:IsIncludeObject( PlayerGroup ) then @@ -330,18 +327,35 @@ function TASK:CrashUnit( PlayerUnit ) local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup ) self:E( { IsGroupAssigned = IsGroupAssigned } ) if IsGroupAssigned then - self:UnAssignFromUnit( PlayerUnit ) - self:MessageToGroups( PlayerUnit:GetPlayerName() .. " crashed in Task " .. self:GetName() ) - self:E( { TaskGroup = PlayerGroup:GetName(), GetUnits = PlayerGroup:GetUnits() } ) - if #PlayerGroup:GetUnits() == 1 then - self:ClearGroupAssignment( PlayerGroup ) + local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName() + self:MessageToGroups( PlayerName .. " crashed! " ) + self:UnAssignFromGroup( PlayerGroup ) + + -- Now check if the task needs to go to hold... + -- It will go to hold, if there are no players in the mission... + + PlayerGroups:Flush() + local IsRemaining = false + for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do + if self:IsGroupAssigned( AssignedGroup ) == true then + IsRemaining = true + self:F( { Task = self:GetName(), IsRemaining = IsRemaining } ) + break + end end - self:PlayerCrashed( PlayerUnit ) + + self:F( { Task = self:GetName(), IsRemaining = IsRemaining } ) + if IsRemaining == false then + self:Abort() + end + + self:PlayerCrashed( PlayerGroup:GetUnit(1) ) end + end end - return PlayerUnitCrashed + return self end From c9121ed6726a8fb71e93aedec703933f996312df Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 5 May 2017 19:50:17 +0200 Subject: [PATCH 06/32] Menu fixes and Report Fixes -- Added player count to plannes task menus -- Detailed task report only shows the players in the task. -- Added method GetPlayerNames for a Task -- Added method GetPlayerCount for a Task -- Started with a threat level implementation on the menus, but there is a problem with the refresh... --- Moose Development/Moose/Tasking/Task.lua | 85 ++++++++++++++----- .../Moose/Tasking/Task_A2G_Dispatcher.lua | 7 +- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index cf306bfee..f006c584f 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -693,7 +693,12 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime ) local CommandCenterMenu = CommandCenter:GetMenu() local TaskType = self:GetType() - local TaskText = self:GetName() +-- local TaskThreatLevel = self.TaskInfo["ThreatLevel"] +-- local TaskThreatLevelString = TaskThreatLevel and " [" .. string.rep( "■", TaskThreatLevel ) .. "]" or " []" + local TaskPlayerCount = self:GetPlayerCount() + local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount ) + local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString ) + local TaskName = string.format( "%s", self:GetName() ) local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime ) @@ -702,10 +707,10 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime ) local TaskPlannedMenu = MENU_GROUP:New( TaskGroup, "Planned Tasks", MissionMenu ):SetTime( MenuTime ) local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, TaskPlannedMenu ):SetTime( MenuTime ):SetRemoveParent( true ) local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetRemoveParent( true ) - local ReportTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task %s Status", TaskText ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) + local ReportTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) if not Mission:IsGroupAssigned( TaskGroup ) then - local JoinTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Join Task %s", TaskText ), TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ):SetTime( MenuTime ):SetRemoveParent( true ) + local JoinTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ):SetTime( MenuTime ):SetRemoveParent( true ) end return self @@ -725,15 +730,19 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime ) local CommandCenterMenu = CommandCenter:GetMenu() local TaskType = self:GetType() - local TaskText = self:GetName() +-- local TaskThreatLevel = self.TaskInfo["ThreatLevel"] +-- local TaskThreatLevelString = TaskThreatLevel and " [" .. string.rep( "■", TaskThreatLevel ) .. "]" or " []" + local TaskPlayerCount = self:GetPlayerCount() + local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount ) + local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString ) + local TaskName = string.format( "%s", self:GetName() ) local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime ) local MissionMenu = Mission:GetMenu( TaskGroup ) - - local TaskAssignedMenu = MENU_GROUP:New( TaskGroup, string.format( "Assigned Task %s", TaskText ), MissionMenu ):SetTime( MenuTime ) - local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task %s Status", TaskText ), TaskAssignedMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) - local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Group from Task %s", TaskText ), TaskAssignedMenu, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) + local TaskAssignedMenu = MENU_GROUP:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime ) + local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskAssignedMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) + local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Group from Task" ), TaskAssignedMenu, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true ) return self end @@ -769,9 +778,9 @@ function TASK:RefreshMenus( TaskGroup, MenuTime ) local MissionMenu = Mission:GetMenu( TaskGroup ) - local TaskText = self:GetName() + local TaskName = self:GetName() local PlannedMenu = MissionMenu:GetMenu( "Planned Tasks" ) - local AssignedMenu = MissionMenu:GetMenu( string.format( "Assigned Task %s", TaskText ) ) + local AssignedMenu = MissionMenu:GetMenu( string.format( "Assigned Task %s", TaskName ) ) if PlannedMenu then PlannedMenu:Remove( MenuTime ) @@ -1300,6 +1309,47 @@ function TASK:ReportOverview() --R2.1 fixed report. Now nicely formatted and con return Report:Text() end +--- Create a count of the players in the Task. +-- @param #TASK self +-- @return #number The total number of players in the task. +function TASK:GetPlayerCount() --R2.1 Get a count of the players. + + local PlayerCount = 0 + + -- Loop each Unit active in the Task, and find Player Names. + for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do + local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP + if self:IsGroupAssigned( PlayerGroup ) then + local PlayerNames = PlayerGroup:GetPlayerNames() + PlayerCount = PlayerCount + #PlayerNames + end + end + + return PlayerCount +end + + +--- Create a list of the players in the Task. +-- @param #TASK self +-- @return #map<#string,Wrapper.Group#GROUP> A map of the players +function TASK:GetPlayerNames() --R2.1 Get a map of the players. + + local PlayerNameMap = {} + + -- Loop each Unit active in the Task, and find Player Names. + for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do + local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP + if self:IsGroupAssigned( PlayerGroup ) then + local PlayerNames = PlayerGroup:GetPlayerNames() + for PlayerNameID, PlayerName in pairs( PlayerNames ) do + PlayerNameMap[PlayerName] = PlayerGroup + end + end + end + + return PlayerNameMap +end + --- Create a detailed report of the Task. -- List the Task Status, and the Players assigned to the Task. @@ -1314,18 +1364,13 @@ function TASK:ReportDetails() --R2.1 fixed report. Now nicely formatted and cont -- Determine the status of the Task. local State = self:GetState() - + -- Loop each Unit active in the Task, and find Player Names. - local PlayerNames = {} + local PlayerNames = self:GetPlayerNames() + local PlayerReport = REPORT:New() - for PlayerGroupID, PlayerGroupData in pairs( self:GetGroups():GetSet() ) do - - local PlayerGroup = PlayerGroupData -- Wrapper.Group#GROUP - - PlayerNames = PlayerGroup:GetPlayerNames() - if PlayerNames then - PlayerReport:Add( "Group " .. PlayerGroup:GetCallsign() .. ": " .. table.concat( PlayerNames, ", " ) ) - end + for PlayerName, PlayerGroup in pairs( PlayerNames ) do + PlayerReport:Add( "Group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName ) end local Players = PlayerReport:Text() diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index b1a6e4348..f7101eea4 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -220,7 +220,7 @@ do -- TASK_A2G_DISPATCHER for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem - local DetectedSet = DetectedItem.Set -- Functional.Detection#DETECTION_BASE.DetectedSet + local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT local DetectedZone = DetectedItem.Zone self:E( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } ) DetectedSet:Flush() @@ -258,6 +258,7 @@ do -- TASK_A2G_DISPATCHER self.Tasks[DetectedItemID] = Task Task:SetTargetZone( DetectedZone ) Task:SetDispatcher( self ) + Task:SetInfo( "ThreatLevel", DetectedSet:CalculateThreatLevelA2G() ) Task:SetInfo( "Detection", Detection:DetectedItemReportSummary( DetectedItemID ) ) Task:SetInfo( "Changes", Detection:GetChangeText( DetectedItem ) ) Mission:AddTask( Task ) @@ -277,7 +278,9 @@ do -- TASK_A2G_DISPATCHER Mission:GetCommandCenter():SetMenu() for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - Mission:GetCommandCenter():MessageToGroup( string.format( "Mission *%s* has tasks %s. Subscribe to a task using the Mission *Overlord* radio menu.", Mission:GetName(), TaskReport:Text(", ") ), TaskGroup ) + if not Mission:IsGroupAssigned(TaskGroup) then + Mission:GetCommandCenter():MessageToGroup( string.format( "Mission *%s* has tasks %s. Subscribe to a task using the Mission *Overlord* radio menu.", Mission:GetName(), TaskReport:Text(", ") ), TaskGroup ) + end end end From 192dbadd51f46516301407f21a4e803dcbdd5727 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 5 May 2017 23:16:57 +0200 Subject: [PATCH 07/32] Cargo and smoke --- Moose Development/Moose/Tasking/Task_CARGO.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 7ad7013e9..b3c7b64a9 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -312,7 +312,7 @@ do -- TASK_CARGO self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - self.Cargo = Cargo + self.Cargo = Cargo -- Core.Cargo#CARGO Task:SetCargoPickup( self.Cargo, TaskUnit ) self:__RouteToPickupPoint( -0.1 ) end @@ -326,6 +326,7 @@ do -- TASK_CARGO self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) if TaskUnit:IsAir() then + self.Cargo.CargoObject:GetUnit(1):SmokeRed() self:__Land( -0.1, "Pickup" ) else self:__SelectAction( -0.1 ) From 11c20d57fd2aaab48972df29e6d17820333ddcdc Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 6 May 2017 10:11:22 +0200 Subject: [PATCH 08/32] Fixes -- Cargo deployment -- Mission text in menu -- Event log decrease --- Moose Development/Moose/Core/Cargo.lua | 90 +++++++++---------- Moose Development/Moose/Core/Event.lua | 2 +- Moose Development/Moose/Tasking/Mission.lua | 25 +++--- .../Moose/Tasking/Task_CARGO.lua | 26 ++++-- 4 files changed, 77 insertions(+), 66 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 825bb5084..f5b47b085 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -234,7 +234,7 @@ do -- CARGO function CARGO:New( Type, Name, Weight ) --R2.1 local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:F( { Type, Name, Weight } ) + self:E( { Type, Name, Weight } ) self:SetStartState( "UnLoaded" ) self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) @@ -299,7 +299,7 @@ end -- @param #CARGO self -- @return #CARGO function CARGO:Spawn( PointVec2 ) - self:F() + self:E() end @@ -310,7 +310,7 @@ end -- @param Core.Zone#ZONE_BASE Zone -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. function CARGO:IsInZone( Zone ) - self:F( { Zone } ) + self:E( { Zone } ) if self:IsLoaded() then return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) @@ -329,7 +329,7 @@ end -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 } ) + self:E( { PointVec2 } ) local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) self:T( Distance ) @@ -382,7 +382,7 @@ do -- CARGO_REPRESENTABLE -- @return #CARGO_REPRESENTABLE function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + self:E( { Type, Name, Weight, ReportRadius, NearRadius } ) return self end @@ -393,7 +393,7 @@ do -- CARGO_REPRESENTABLE -- @param #number Speed -- @return #CARGO_REPRESENTABLE function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:F2( ToPointVec2 ) + self:E2( ToPointVec2 ) local Points = {} @@ -429,7 +429,7 @@ end -- CARGO_REPRESENTABLE -- @return #CARGO_REPORTABLE function CARGO_REPORTABLE:New( CargoObject, Type, Name, Weight, ReportRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE - self:F( { Type, Name, Weight, ReportRadius } ) + self:E( { Type, Name, Weight, ReportRadius } ) self.ReportRadius = ReportRadius or 1000 self.CargoObject = CargoObject @@ -442,7 +442,7 @@ end -- CARGO_REPRESENTABLE -- @param Core.Point#POINT_VEC2 PointVec2 -- @return #boolean function CARGO_REPORTABLE:IsInRadius( PointVec2 ) - self:F( { PointVec2 } ) + self:E( { PointVec2 } ) local Distance = 0 if self:IsLoaded() then @@ -513,7 +513,7 @@ do -- CARGO_UNIT -- @return #CARGO_UNIT function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:F( { Type, Name, Weight, NearRadius } ) + self:E( { Type, Name, Weight, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit @@ -542,7 +542,7 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F() + self:E() NearRadius = NearRadius or 25 @@ -599,9 +599,9 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F( { ToPointVec2, From, Event, To } ) + self:E( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 local Angle = 180 local Speed = 10 @@ -625,9 +625,9 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:F( { ToPointVec2, From, Event, To } ) + self:E( { ToPointVec2, From, Event, To } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 self.CargoInAir = self.CargoObject:InAir() @@ -652,7 +652,7 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:F( { ToPointVec2, From, Event, To } ) + self:E( { ToPointVec2, From, Event, To } ) local Angle = 180 local Speed = 10 @@ -687,9 +687,9 @@ end -- @param #string From -- @param #string To function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F() + self:E() - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 self.CargoInAir = self.CargoObject:InAir() @@ -735,9 +735,9 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then self:__Load( 1, CargoCarrier, ... ) @@ -756,11 +756,11 @@ end -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #number NearRadius function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) self:__Boarding( -1, CargoCarrier, NearRadius, ... ) - self:__Board( -15, CargoCarrier, NearRadius, ... ) + self:__Board( -10, CargoCarrier, NearRadius, ... ) end @@ -772,13 +772,13 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) local Speed = 90 local Angle = 180 local Distance = 5 - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 if From == "UnLoaded" or From == "Boarding" then @@ -793,7 +793,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:F() + self:E( { From, Event, To, CargoCarrier } ) self.CargoCarrier = CargoCarrier @@ -827,7 +827,7 @@ do -- CARGO_PACKAGE -- @return #CARGO_PACKAGE function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE - self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + self:E( { Type, Name, Weight, ReportRadius, NearRadius } ) self:T( CargoCarrier ) self.CargoCarrier = CargoCarrier @@ -845,7 +845,7 @@ end -- @param #number BoardDistance -- @param #number Angle function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() + self:E() self.CargoInAir = self.CargoCarrier:InAir() @@ -878,7 +878,7 @@ end -- @param Wrapper.Unit#UNIT CargoCarrier -- @return #boolean function CARGO_PACKAGE:IsNear( CargoCarrier ) - self:F() + self:E() local CargoCarrierPoint = CargoCarrier:GetPointVec2() @@ -899,7 +899,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:F() + self:E() if self:IsNear( CargoCarrier ) then self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) @@ -919,7 +919,7 @@ end -- @param #number Radius -- @param #number Angle function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:F() + self:E() self.CargoInAir = self.CargoCarrier:InAir() @@ -957,7 +957,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:F() + self:E() if self:IsNear( CargoCarrier ) then self:__UnLoad( 1, CargoCarrier, Speed ) @@ -976,7 +976,7 @@ end -- @param #number LoadDistance -- @param #number Angle function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:F() + self:E() self.CargoCarrier = CargoCarrier @@ -1002,7 +1002,7 @@ end -- @param #number Distance -- @param #number Angle function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) - self:F() + self:E() local StartPointVec2 = self.CargoCarrier:GetPointVec2() local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. @@ -1049,7 +1049,7 @@ do -- CARGO_GROUP -- @return #CARGO_GROUP function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) + self:E( { Type, Name, ReportRadius } ) self.CargoSet = SET_CARGO:New() @@ -1082,9 +1082,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) + self:E( { CargoCarrier.UnitName, From, Event, To } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 if From == "UnLoaded" then @@ -1107,7 +1107,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) + self:E( { CargoCarrier.UnitName, From, Event, To } ) if From == "UnLoaded" then -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. @@ -1128,9 +1128,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) + self:E( { CargoCarrier.UnitName, From, Event, To } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 local Boarded = true @@ -1159,9 +1159,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F({From, Event, To, ToPointVec2, NearRadius}) + self:E( {From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 local Timer = 1 @@ -1187,9 +1187,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) + self:E( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 local Angle = 180 local Speed = 10 @@ -1224,9 +1224,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) + self:E( { From, Event, To, ToPointVec2, NearRadius } ) - NearRadius = NearRadius or 25 + local NearRadius = NearRadius or 25 self:__UnLoad( 1, ToPointVec2, ... ) end @@ -1240,7 +1240,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:F( { From, Event, To, ToPointVec2 } ) + self:E( { From, Event, To, ToPointVec2 } ) if From == "Loaded" then diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index f37e590df..f9da8ec67 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -890,7 +890,7 @@ function EVENT:onEvent( Event ) for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do if Event.IniObjectCategory ~= Object.Category.STATIC then - self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) + --self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) end Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 751768130..73d7a84fa 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -27,6 +27,18 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM + self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } ) + + self.CommandCenter = CommandCenter + CommandCenter:AddMission( self ) + + self.Name = MissionName + self.MissionPriority = MissionPriority + self.MissionBriefing = MissionBriefing + self.MissionCoalition = MissionCoalition + + self.Tasks = {} + self:SetStartState( "IDLE" ) self:AddTransition( "IDLE", "Start", "ENGAGED" ) @@ -208,17 +220,6 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi -- @param #MISSION self -- @param #number Delay The delay in seconds. - self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } ) - - self.CommandCenter = CommandCenter - CommandCenter:AddMission( self ) - - self.Name = MissionName - self.MissionPriority = MissionPriority - self.MissionBriefing = MissionBriefing - self.MissionCoalition = MissionCoalition - - self.Tasks = {} -- Private implementations @@ -257,7 +258,7 @@ end -- @param #MISSION self -- @return #MISSION self function MISSION:GetName() - return self.Name + return string.format( "Mission %s (%s)", self.Name, self.MissionPriority ) end --- Add a Unit to join the Mission. diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index b3c7b64a9..d80324af6 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -211,7 +211,7 @@ do -- TASK_CARGO --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit - -- @param Tasking.Task_Cargo#TASK_CARGO Task + -- @param Tasking.Task_CARGO#TASK_CARGO Task function Fsm:onenterWaitingForCommand( TaskUnit, Task ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) @@ -472,31 +472,41 @@ do -- TASK_CARGO -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task + -- @param From + -- @param Event + -- @param To + -- @param Cargo + -- @param Core.Zone#ZONE_BASE DeployZone function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo, DeployZone ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo, DeployZone } ) self.Cargo = Cargo - self.DeployZone = DeployZone - self:__UnBoard( -0.1 ) + self.DeployZone = DeployZone -- Core.Zone#ZONE_BASE + self:__UnBoard( -0.1, Cargo, DeployZone ) end --- -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task - function Fsm:onafterUnBoard( TaskUnit, Task ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- @param From + -- @param Event + -- @param To + -- @param Cargo + -- @param Core.Zone#ZONE_BASE DeployZone + function Fsm:onafterUnBoard( TaskUnit, Task, From, Event, To, Cargo, DeployZone ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo, DeployZone } ) function self.Cargo:OnEnterUnLoaded( From, Event, To, DeployZone, TaskProcess ) - self:E({From, Event, To, TaskUnit, TaskProcess }) + self:E({From, Event, To, DeployZone, TaskProcess }) TaskProcess:__UnBoarded( -0.1 ) end self.Cargo:MessageToGroup( "UnBoarding ...", TaskUnit:GetGroup() ) - self.Cargo:UnBoard( self.DeployZone:GetPointVec2(), 20, self ) + self.Cargo:UnBoard( DeployZone:GetPointVec2(), 400, self ) end From d2d59a7ba337d617f72a7e52f78f7ea59fd56d4a Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 6 May 2017 23:06:21 +0200 Subject: [PATCH 09/32] Fixes cargo --- Moose Development/Moose/Core/Cargo.lua | 92 ++++++++++++++------------ 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index f5b47b085..65414e1f8 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -234,7 +234,7 @@ do -- CARGO function CARGO:New( Type, Name, Weight ) --R2.1 local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:E( { Type, Name, Weight } ) + self:F( { Type, Name, Weight } ) self:SetStartState( "UnLoaded" ) self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) @@ -299,7 +299,7 @@ end -- @param #CARGO self -- @return #CARGO function CARGO:Spawn( PointVec2 ) - self:E() + self:F() end @@ -310,7 +310,7 @@ end -- @param Core.Zone#ZONE_BASE Zone -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. function CARGO:IsInZone( Zone ) - self:E( { Zone } ) + self:F( { Zone } ) if self:IsLoaded() then return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) @@ -329,7 +329,7 @@ end -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:E( { PointVec2 } ) + self:F( { PointVec2, NearRadius } ) local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) self:T( Distance ) @@ -382,7 +382,7 @@ do -- CARGO_REPRESENTABLE -- @return #CARGO_REPRESENTABLE function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, ReportRadius, NearRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE - self:E( { Type, Name, Weight, ReportRadius, NearRadius } ) + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) return self end @@ -393,7 +393,7 @@ do -- CARGO_REPRESENTABLE -- @param #number Speed -- @return #CARGO_REPRESENTABLE function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:E2( ToPointVec2 ) + self:F2( ToPointVec2 ) local Points = {} @@ -429,7 +429,7 @@ end -- CARGO_REPRESENTABLE -- @return #CARGO_REPORTABLE function CARGO_REPORTABLE:New( CargoObject, Type, Name, Weight, ReportRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE - self:E( { Type, Name, Weight, ReportRadius } ) + self:F( { Type, Name, Weight, ReportRadius } ) self.ReportRadius = ReportRadius or 1000 self.CargoObject = CargoObject @@ -442,7 +442,7 @@ end -- CARGO_REPRESENTABLE -- @param Core.Point#POINT_VEC2 PointVec2 -- @return #boolean function CARGO_REPORTABLE:IsInRadius( PointVec2 ) - self:E( { PointVec2 } ) + self:F( { PointVec2 } ) local Distance = 0 if self:IsLoaded() then @@ -513,7 +513,7 @@ do -- CARGO_UNIT -- @return #CARGO_UNIT function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:E( { Type, Name, Weight, NearRadius } ) + self:F( { Type, Name, Weight, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit @@ -542,7 +542,7 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:E() + self:F( { From, Event, To, ToPointVec2, NearRadius } ) NearRadius = NearRadius or 25 @@ -575,7 +575,7 @@ function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius -- Respawn the group... if self.CargoObject then self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading ) - self:E( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) self.CargoCarrier = nil local Points = {} @@ -586,7 +586,8 @@ function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius local TaskRoute = self.CargoObject:TaskRoute( Points ) self.CargoObject:SetTask( TaskRoute, 1 ) - self:__UnBoarding( -1, ToPointVec2, NearRadius ) + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) end end @@ -599,9 +600,9 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:E( { From, Event, To, ToPointVec2, NearRadius } ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) - local NearRadius = NearRadius or 25 + NearRadius = NearRadius or 25 local Angle = 180 local Speed = 10 @@ -611,6 +612,7 @@ function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius if self:IsNear( ToPointVec2, NearRadius ) then return true else + self:__UnBoarding( 1, ToPointVec2, NearRadius ) end return false @@ -625,9 +627,9 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:E( { ToPointVec2, From, Event, To } ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) - local NearRadius = NearRadius or 25 + NearRadius = NearRadius or 25 self.CargoInAir = self.CargoObject:InAir() @@ -639,7 +641,7 @@ function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius end - self:__UnLoad( 1, ToPointVec2 ) + self:__UnLoad( 1, ToPointVec2, NearRadius ) end @@ -652,7 +654,7 @@ end -- @param #string To -- @param Core.Point#POINT_VEC2 function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:E( { ToPointVec2, From, Event, To } ) + self:F( { ToPointVec2, From, Event, To } ) local Angle = 180 local Speed = 10 @@ -687,7 +689,7 @@ end -- @param #string From -- @param #string To function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E() + self:F( { From, Event, To, CargoCarrier, NearRadius } ) local NearRadius = NearRadius or 25 @@ -735,7 +737,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) local NearRadius = NearRadius or 25 @@ -756,7 +758,7 @@ end -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #number NearRadius function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) self:__Boarding( -1, CargoCarrier, NearRadius, ... ) @@ -772,7 +774,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) + self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) local Speed = 90 local Angle = 180 @@ -793,7 +795,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:E( { From, Event, To, CargoCarrier } ) + self:F( { From, Event, To, CargoCarrier } ) self.CargoCarrier = CargoCarrier @@ -827,7 +829,7 @@ do -- CARGO_PACKAGE -- @return #CARGO_PACKAGE function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, ReportRadius, NearRadius ) ) -- #CARGO_PACKAGE - self:E( { Type, Name, Weight, ReportRadius, NearRadius } ) + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) self:T( CargoCarrier ) self.CargoCarrier = CargoCarrier @@ -845,7 +847,7 @@ end -- @param #number BoardDistance -- @param #number Angle function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:E() + self:F() self.CargoInAir = self.CargoCarrier:InAir() @@ -878,7 +880,7 @@ end -- @param Wrapper.Unit#UNIT CargoCarrier -- @return #boolean function CARGO_PACKAGE:IsNear( CargoCarrier ) - self:E() + self:F() local CargoCarrierPoint = CargoCarrier:GetPointVec2() @@ -899,7 +901,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:E() + self:F() if self:IsNear( CargoCarrier ) then self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) @@ -919,7 +921,7 @@ end -- @param #number Radius -- @param #number Angle function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:E() + self:F() self.CargoInAir = self.CargoCarrier:InAir() @@ -957,7 +959,7 @@ end -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:E() + self:F() if self:IsNear( CargoCarrier ) then self:__UnLoad( 1, CargoCarrier, Speed ) @@ -976,7 +978,7 @@ end -- @param #number LoadDistance -- @param #number Angle function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:E() + self:F() self.CargoCarrier = CargoCarrier @@ -1002,7 +1004,7 @@ end -- @param #number Distance -- @param #number Angle function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) - self:E() + self:F() local StartPointVec2 = self.CargoCarrier:GetPointVec2() local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. @@ -1049,7 +1051,7 @@ do -- CARGO_GROUP -- @return #CARGO_GROUP function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:E( { Type, Name, ReportRadius } ) + self:F( { Type, Name, ReportRadius } ) self.CargoSet = SET_CARGO:New() @@ -1082,7 +1084,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E( { CargoCarrier.UnitName, From, Event, To } ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) local NearRadius = NearRadius or 25 @@ -1107,7 +1109,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:E( { CargoCarrier.UnitName, From, Event, To } ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) if From == "UnLoaded" then -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. @@ -1128,7 +1130,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:E( { CargoCarrier.UnitName, From, Event, To } ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) local NearRadius = NearRadius or 25 @@ -1159,9 +1161,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:E( {From, Event, To, ToPointVec2, NearRadius } ) + self:F( {From, Event, To, ToPointVec2, NearRadius } ) - local NearRadius = NearRadius or 25 + NearRadius = NearRadius or 25 local Timer = 1 @@ -1169,12 +1171,14 @@ function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 self.CargoSet:ForEach( - function( Cargo ) + function( Cargo, NearRadius ) + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) Timer = Timer + 10 - end + end, { NearRadius } ) + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) end @@ -1187,9 +1191,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:E( { From, Event, To, ToPointVec2, NearRadius } ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) - local NearRadius = NearRadius or 25 + --local NearRadius = NearRadius or 25 local Angle = 180 local Speed = 10 @@ -1224,9 +1228,9 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:E( { From, Event, To, ToPointVec2, NearRadius } ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) - local NearRadius = NearRadius or 25 + --local NearRadius = NearRadius or 25 self:__UnLoad( 1, ToPointVec2, ... ) end @@ -1240,7 +1244,7 @@ end -- @param #string From -- @param #string To function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:E( { From, Event, To, ToPointVec2 } ) + self:F( { From, Event, To, ToPointVec2 } ) if From == "Loaded" then From 2fadd949a6f841e7bf5bd2aea781d75f023bb894 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 7 May 2017 15:37:27 +0200 Subject: [PATCH 10/32] Fixes --- .../Moose/Actions/Act_Assign.lua | 2 - Moose Development/Moose/Core/Cargo.lua | 8 ++ Moose Development/Moose/Core/Set.lua | 5 + .../Moose/Tasking/CommandCenter.lua | 44 +++++-- Moose Development/Moose/Tasking/Mission.lua | 117 +++++++++++++++++- Moose Development/Moose/Tasking/Task.lua | 50 +++++--- Moose Development/Moose/Tasking/Task_A2G.lua | 71 ++++++++--- .../Moose/Tasking/Task_CARGO.lua | 36 ++++-- .../Moose/Wrapper/Positionable.lua | 13 +- 9 files changed, 280 insertions(+), 66 deletions(-) diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 7d45ad21a..e04139698 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -173,8 +173,6 @@ do -- ACT_ASSIGN_ACCEPT local ProcessGroup = ProcessUnit:GetGroup() - self:Message( "You are assigned to the task " .. self.Task:GetName() ) - self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() ) end diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 65414e1f8..f984fe542 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -280,6 +280,14 @@ function CARGO:GetType() return self.Type end +--- Get the current coordinates of the Cargo. +-- @param #CARGO self +-- @return Core.Point#COORDINATE The coordinates of the Cargo. +function CARGO:GetCoordinate() + return self.CargoObject:GetCoordinate() +end + + --- Check if cargo is loaded. -- @param #CARGO self -- @return #boolean true if loaded diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index aaa06e3a8..6ca7f6d5d 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1336,6 +1336,11 @@ SET_UNIT = { } +--- Get the first unit from the set. +-- @function [parent=#SET_UNIT] GetFirst +-- @param #SET_UNIT self +-- @return Wrapper.Unit#UNIT The UNIT object. + --- Creates a new SET_UNIT object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. -- @param #SET_UNIT self -- @return #SET_UNIT diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 248f5fd00..93fd01162 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -112,9 +112,9 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName ) if EventData.IniObjectCategory == 1 then local EventGroup = GROUP:Find( EventData.IniDCSGroup ) if EventGroup and self:HasGroup( EventGroup ) then - local MenuReporting = MENU_GROUP:New( EventGroup, "Reporting", self.CommandCenterMenu ) - local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Summary Report", MenuReporting, self.ReportSummary, self, EventGroup ) - local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Details Report", MenuReporting, self.ReportDetails, self, EventGroup ) + local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", self.CommandCenterMenu ) + local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportMissionsStatus, self, EventGroup ) + local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup ) self:ReportSummary( EventGroup ) end local PlayerUnit = EventData.IniUnit @@ -307,11 +307,9 @@ end -- @param #string Message -- @param Wrapper.Group#GROUP TaskGroup -- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. -function COMMANDCENTER:MessageToGroup( Message, TaskGroup, Name ) +function COMMANDCENTER:MessageToGroup( Message, TaskGroup ) - local Prefix = Name and "@ " .. Name .. ": " or "@ " .. TaskGroup:GetCallsign() .. ": " - Message = Prefix .. Message - self:GetPositionable():MessageToGroup( Message , 20, TaskGroup, self:GetName() ) + self:GetPositionable():MessageToGroup( Message , 15, TaskGroup, self:GetName() ) end @@ -321,7 +319,8 @@ function COMMANDCENTER:MessageToCoalition( Message ) local CCCoalition = self:GetPositionable():GetCoalition() --TODO: Fix coalition bug! - self:GetPositionable():MessageToCoalition( Message, 20, CCCoalition, self:GetName() ) + + self:GetPositionable():MessageToCoalition( Message, 15, CCCoalition ) end @@ -329,18 +328,37 @@ end --- Report the status of all MISSIONs to a GROUP. -- Each Mission is listed, with an indication how many Tasks are still to be completed. -- @param #COMMANDCENTER self -function COMMANDCENTER:ReportSummary( ReportGroup ) +function COMMANDCENTER:ReportMissionsStatus( ReportGroup ) + self:E( ReportGroup ) + + local Report = REPORT:New() + + Report:Add( "Status report of all missions." ) + + for MissionID, Mission in pairs( self.Missions ) do + local Mission = Mission -- Tasking.Mission#MISSION + Report:Add( " - " .. Mission:ReportStatus() ) + end + + self:MessageToGroup( Report:Text(), ReportGroup ) +end + +--- Report the players of all MISSIONs to a GROUP. +-- Each Mission is listed, with an indication how many Tasks are still to be completed. +-- @param #COMMANDCENTER self +function COMMANDCENTER:ReportMissionsPlayers( ReportGroup ) self:E( ReportGroup ) local Report = REPORT:New() + Report:Add( "Players active in all missions." ) + for MissionID, Mission in pairs( self.Missions ) do local Mission = Mission -- Tasking.Mission#MISSION - Report:Add( " - " .. Mission:ReportOverview() ) + Report:Add( " - " .. Mission:ReportPlayers() ) end - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) - + self:MessageToGroup( Report:Text(), ReportGroup ) end --- Report the status of a Task to a Group. @@ -356,6 +374,6 @@ function COMMANDCENTER:ReportDetails( ReportGroup, Task ) Report:Add( " - " .. Mission:ReportDetails() ) end - self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup ) + self:MessageToGroup( Report:Text(), ReportGroup ) end diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 73d7a84fa..47563623e 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -258,7 +258,7 @@ end -- @param #MISSION self -- @return #MISSION self function MISSION:GetName() - return string.format( "Mission %s (%s)", self.Name, self.MissionPriority ) + return string.format( 'Mission "%s (%s)"', self.Name, self.MissionPriority ) end --- Add a Unit to join the Mission. @@ -606,6 +606,117 @@ function MISSION:GetTasksRemaining() return TasksRemaining end +--- @param #MISSION self +-- @return #number +function MISSION:GetTaskTypes() + -- Determine how many tasks are remaining. + local TaskTypeList = {} + local TasksRemaining = 0 + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + local TaskType = Task:GetType() + TaskTypeList[TaskType] = TaskType + end + return TaskTypeList +end + + +--- Create a status report of the Mission. +-- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks. +-- +-- Mission "" - Status "" +-- - Task Types: , +-- - Planned Tasks (xp) +-- - Assigned Tasks(xp) +-- - Success Tasks (xp) +-- - Hold Tasks (xp) +-- - Cancelled Tasks (xp) +-- - Aborted Tasks (xp) +-- - Failed Tasks (xp) +-- +-- @param #MISSION self +-- @return #string +function MISSION:ReportStatus() + + local Report = REPORT:New() + + -- List the name of the mission. + local Name = self:GetName() + + -- Determine the status of the mission. + local Status = self:GetState() + local TasksRemaining = self:GetTasksRemaining() + + Report:Add( string.format( '%s - Status "%s"', Name, Status ) ) + + local TaskTypes = self:GetTaskTypes() + + Report:Add( string.format( " - Task Types: %s", table.concat(TaskTypes, ", " ) ) ) + + local TaskStatusList = { "Planned", "Assigned", "Success", "Hold", "Cancelled", "Aborted", "Failed" } + + for TaskStatusID, TaskStatus in pairs( TaskStatusList ) do + local TaskCount = 0 + local TaskPlayerCount = 0 + -- Determine how many tasks are remaining. + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + if Task:Is( TaskStatus ) then + TaskCount = TaskCount + 1 + TaskPlayerCount = TaskPlayerCount + Task:GetPlayerCount() + end + end + if TaskCount > 0 then + Report:Add( string.format( " - %02d %s Tasks (%dp)", TaskCount, TaskStatus, TaskPlayerCount ) ) + end + end + + return Report:Text() +end + +--- Create a player report of the Mission. +-- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks. +-- +-- Mission "" - Status "" +-- - Player ": Task , Task +-- - Player : Task , Task +-- - .. +-- +-- @param #MISSION self +-- @return #string +function MISSION:ReportPlayers() + + local Report = REPORT:New() + + -- List the name of the mission. + local Name = self:GetName() + + -- Determine the status of the mission. + local Status = self:GetState() + local TasksRemaining = self:GetTasksRemaining() + + Report:Add( string.format( '%s - Status "%s"', Name, Status ) ) + + local PlayerList = {} + + -- Determine how many tasks are remaining. + for TaskID, Task in pairs( self:GetTasks() ) do + local Task = Task -- Tasking.Task#TASK + local PlayerNames = Task:GetPlayerNames() + for PlayerID, PlayerName in pairs( PlayerNames ) do + PlayerList[PlayerName] = Task:GetName() + end + + end + + for PlayerName, TaskName in pairs( PlayerList ) do + Report:Add( string.format( ' - Player (%s): Task "%s"', PlayerName, TaskName ) ) + end + + return Report:Text() +end + + --- Create a summary report of the Mission (one line). -- @param #MISSION self -- @return #string @@ -645,7 +756,7 @@ function MISSION:ReportOverview( TaskStatus ) local Status = self:GetState() local TasksRemaining = self:GetTasksRemaining() - Report:Add( "Mission " .. Name .. " - " .. Status .. " Task Report ") + Report:Add( string.format( '%s - Status "%s"', Name, Status ) ) -- Determine how many tasks are remaining. local TasksRemaining = 0 @@ -672,7 +783,7 @@ function MISSION:ReportDetails() -- Determine the status of the mission. local Status = self:GetState() - Report:Add( "Mission " .. Name .. " - " .. Status ) + Report:Add( string.format( '%s - Status "%s"', Name, Status ) ) -- Determine how many tasks are remaining. local TasksRemaining = 0 diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index f006c584f..e2ae85c64 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -157,9 +157,9 @@ TASK = { -- @param #string TaskName The name of the Task -- @param #string TaskType The type of the Task -- @return #TASK self -function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) +function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) - local self = BASE:Inherit( self, FSM_TASK:New() ) -- Core.Fsm#FSM_TASK + local self = BASE:Inherit( self, FSM_TASK:New() ) -- Tasking.Task#TASK self:SetStartState( "Planned" ) self:AddTransition( "Planned", "Assign", "Assigned" ) @@ -189,7 +189,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType ) self:SetName( TaskName ) self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences .. - self.TaskBriefing = "You are invited for the task: " .. self.TaskName .. "." + self:SetBriefing( TaskBriefing ) self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New() @@ -413,15 +413,15 @@ do -- Group Assignment local SetAssignedGroups = self:GetGroups() - SetAssignedGroups:ForEachGroup( - function( AssignedGroup ) - if self:IsGroupAssigned(AssignedGroup) then - self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to group %s.", TaskName, TaskGroupName ), AssignedGroup ) - else - self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to your group.", TaskName ), AssignedGroup ) - end - end - ) +-- SetAssignedGroups:ForEachGroup( +-- function( AssignedGroup ) +-- if self:IsGroupAssigned(AssignedGroup) then +-- self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to group %s.", TaskName, TaskGroupName ), AssignedGroup ) +-- else +-- self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is assigned to your group.", TaskName ), AssignedGroup ) +-- end +-- end +-- ) return self end @@ -468,6 +468,8 @@ do -- Group Assignment self:F( TaskGroup:GetName() ) local TaskGroupName = TaskGroup:GetName() + local Mission = self:GetMission() + local CommandCenter = Mission:GetCommandCenter() self:SetGroupAssigned( TaskGroup ) @@ -478,11 +480,16 @@ do -- Group Assignment self:E(PlayerName) if PlayerName ~= nil or PlayerName ~= "" then self:AssignToUnit( TaskUnit ) + CommandCenter:MessageToGroup( + string.format( 'Task "%s": Briefing for player (%s):\n%s', + self:GetName(), + PlayerName, + self:GetBriefing() + ), TaskGroup + ) end end - local Mission = self:GetMission() - local CommandCenter = Mission:GetCommandCenter() CommandCenter:SetMenu() return self @@ -848,6 +855,13 @@ function TASK:GetTaskName() return self.TaskName end +--- Returns the @{Task} briefing. +-- @param #TASK self +-- @return #string Task briefing. +function TASK:GetTaskBriefing() + return self.TaskBriefing +end + @@ -1117,10 +1131,18 @@ end -- @param #string TaskBriefing -- @return #TASK self function TASK:SetBriefing( TaskBriefing ) + self:E(TaskBriefing) self.TaskBriefing = TaskBriefing return self end +--- Gets the @{Task} briefing. +-- @param #TASK self +-- @return #string The briefing text. +function TASK:GetBriefing() + return self.TaskBriefing +end + diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 17162ca7f..8c99d85f1 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -86,8 +86,8 @@ do -- TASK_A2G -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. -- @return #TASK_A2G self - function TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskType ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) -- Tasking.Task#TASK_A2G + function TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskType, TaskBriefing ) + local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- Tasking.Task#TASK_A2G self:F() self.TargetSetUnit = TargetSetUnit @@ -364,16 +364,28 @@ do -- TASK_SEAD --- Instantiates a new TASK_SEAD. -- @param #TASK_SEAD self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT TargetSetUnit + -- @param Core.Set#SET_UNIT TargetSetUnit + -- @param #string TaskBriefing The briefing of the task. -- @return #TASK_SEAD self - function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit ) - local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD" ) ) -- #TASK_SEAD + function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD", TaskBriefing ) ) -- #TASK_SEAD self:F() Mission:AddTask( self ) + local TargetCoord = TargetSetUnit:GetFirst():GetCoordinate() + local TargetPositionText = TargetCoord:ToString() + local TargetThreatLevel = TargetSetUnit:CalculateThreatLevelA2G() + + self:SetBriefing( + TaskBriefing or + "Execute a Suppression of Enemy Air Defenses.\n" .. + "Initial Coordinates: " .. TargetPositionText .. "\n" .. + "Threat Level: [" .. string.rep( "■", TargetThreatLevel ) .. "]" + ) + return self end @@ -392,19 +404,28 @@ do -- TASK_BAI --- Instantiates a new TASK_BAI. -- @param #TASK_BAI self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets - -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. - -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. - -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. + -- @param Core.Set#SET_UNIT TargetSetUnit + -- @param #string TaskBriefing The briefing of the task. -- @return #TASK_BAI self - function TASK_BAI:New( Mission, SetGroup, TaskName, TargetSetUnit ) - local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "BAI" ) ) -- #TASK_BAI + function TASK_BAI:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "BAI", TaskBriefing ) ) -- #TASK_BAI self:F() Mission:AddTask( self ) + local TargetCoord = TargetSetUnit:GetFirst():GetCoordinate() + local TargetPositionText = TargetCoord:ToString() + local TargetThreatLevel = TargetSetUnit:CalculateThreatLevelA2G() + + self:SetBriefing( + TaskBriefing or + "Execute a Battleground Air Interdiction of a group of enemy targets.\n" .. + "Initial Coordinates: " .. TargetPositionText .. "\n" .. + "Threat Level: [" .. string.rep( "■", TargetThreatLevel ) .. "]" + ) + return self end @@ -423,19 +444,29 @@ do -- TASK_CAS --- Instantiates a new TASK_CAS. -- @param #TASK_CAS self -- @param Tasking.Mission#MISSION Mission - -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. - -- @param Set#SET_UNIT UnitSetTargets - -- @param #number TargetDistance The distance to Target when the Player is considered to have "arrived" at the engagement range. - -- @param Core.Zone#ZONE_BASE TargetZone The target zone, if known. - -- If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be. + -- @param Core.Set#SET_UNIT TargetSetUnit + -- @param #string TaskBriefing The briefing of the task. -- @return #TASK_CAS self - function TASK_CAS:New( Mission, SetGroup, TaskName, TargetSetUnit ) - local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "CAS" ) ) -- #TASK_CAS + function TASK_CAS:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing ) + local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "CAS", TaskBriefing ) ) -- #TASK_CAS self:F() Mission:AddTask( self ) + local TargetCoord = TargetSetUnit:GetFirst():GetCoordinate() + local TargetPositionText = TargetCoord:ToString() + local TargetThreatLevel = TargetSetUnit:CalculateThreatLevelA2G() + + self:SetBriefing( + TaskBriefing or + "Execute a Close Air Support for a group of enemy targets.\n" .. + "Beware of friendlies at the vicinity!\n" .. + "Initial Coordinates: " .. TargetPositionText .. "\n" .. + "Threat Level: [" .. string.rep( "■", TargetThreatLevel ) .. "]" + ) + return self end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index d80324af6..38d5c2316 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -153,7 +153,7 @@ do -- TASK_CARGO -- -- === -- - -- @field #TASK_CARGO TASK_CARGO + -- @field #TASK_CARGO -- TASK_CARGO = { ClassName = "TASK_CARGO", @@ -166,9 +166,10 @@ do -- TASK_CARGO -- @param #string TaskName The name of the Task. -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. -- @param #string TaskType The type of Cargo task. + -- @param #string TaskBriefing The Cargo Task briefing. -- @return #TASK_CARGO self - function TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, TaskType ) - local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType ) ) -- #TASK_CARGO + function TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, TaskType, TaskBriefing ) + local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- #TASK_CARGO self:F( {Mission, SetGroup, TaskName, SetCargo, TaskType}) self.SetCargo = SetCargo @@ -696,9 +697,10 @@ do -- TASK_CARGO_TRANSPORT -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task. -- @param Core.Set#SET_CARGO SetCargo The scope of the cargo to be transported. + -- @param #string TaskBriefing The Cargo Task briefing. -- @return #TASK_CARGO_TRANSPORT self - function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo ) - local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport" ) ) -- #TASK_CARGO_TRANSPORT + function TASK_CARGO_TRANSPORT:New( Mission, SetGroup, TaskName, SetCargo, TaskBriefing ) + local self = BASE:Inherit( self, TASK_CARGO:New( Mission, SetGroup, TaskName, SetCargo, "Transport", TaskBriefing ) ) -- #TASK_CARGO_TRANSPORT self:F() Mission:AddTask( self ) @@ -709,8 +711,6 @@ do -- TASK_CARGO_TRANSPORT self:AddTransition( "*", "CargoPickedUp", "*" ) self:AddTransition( "*", "CargoDeployed", "*" ) - do - --- OnBefore Transition Handler for Event CargoPickedUp. -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp -- @param #TASK_CARGO_TRANSPORT self @@ -742,9 +742,7 @@ do -- TASK_CARGO_TRANSPORT -- @param #number Delay The delay in seconds. -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc. -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. - end - do --- OnBefore Transition Handler for Event CargoDeployed. -- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoDeployed -- @param #TASK_CARGO_TRANSPORT self @@ -780,10 +778,26 @@ do -- TASK_CARGO_TRANSPORT -- @param Wrapper.Unit#UNIT TaskUnit The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc. -- @param Core.Cargo#CARGO Cargo The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status. -- @param Core.Zone#ZONE DeployZone The zone where the Cargo got Deployed or UnBoarded. - end local Fsm = self:GetUnitProcess() + local CargoReport = REPORT:New( "Transport Cargo. The following cargo needs to be transported including initial positions:") + + SetCargo:ForEachCargo( + --- @param Core.Cargo#CARGO Cargo + function( Cargo ) + local CargoType = Cargo:GetType() + local CargoName = Cargo:GetName() + local CargoCoordinate = Cargo:GetCoordinate() + CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToString() ) ) + end + ) + + self:SetBriefing( + TaskBriefing or + CargoReport:Text() + ) + return self end @@ -815,7 +829,7 @@ do -- TASK_CARGO_TRANSPORT end end end - + return CargoDeployed end diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 7a192ba64..c815b7bfb 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -334,7 +334,7 @@ function POSITIONABLE:GetMessageText( Message, Name ) --R2.1 added local DCSObject = self:GetDCSObject() if DCSObject then Name = Name and ( " (" .. Name .. ")" ) or "" - local Callsign = self:GetCallsign() ~= "" and self:GetCallsign() or self:GetName() + local Callsign = string.format( "[%s]", self:GetCallsign() ~= "" and self:GetCallsign() or self:GetName() ) local MessageText = Callsign .. Name .. ": " .. Message return MessageText end @@ -383,12 +383,19 @@ end -- @param #string Message The message text -- @param Dcs.DCSTYpes#Duration Duration The duration of the message. -- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message. --- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable. -function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, Name ) +function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition ) self:F2( { Message, Duration } ) + local Name = "" + local DCSObject = self:GetDCSObject() if DCSObject then + if MessageCoalition == coalition.side.BLUE then + Name = "Blue coalition" + end + if MessageCoalition == coalition.side.RED then + Name = "Red coalition" + end self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition ) end From 3329465fd313c70453b5f05b405e890b2f6fc072 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 8 May 2017 14:57:16 +0200 Subject: [PATCH 11/32] Improved boarding process Fixed boarding process when a carrier would ascend while boarding, the boarding process would be cancelled by the cargo. the carrier is notified of that event. When the carrier lands again, he can again board the cargo using the cargo menu options. --- Moose Development/Moose/Core/Cargo.lua | 548 +++++++++--------- .../Moose/Tasking/Task_CARGO.lua | 6 +- 2 files changed, 291 insertions(+), 263 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index f984fe542..281d81224 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -239,6 +239,7 @@ function CARGO:New( Type, Name, Weight ) --R2.1 self:SetStartState( "UnLoaded" ) self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) self:AddTransition( "Boarding" , "Boarding", "Boarding" ) + self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) self:AddTransition( "Boarding", "Load", "Loaded" ) self:AddTransition( "UnLoaded", "Load", "Loaded" ) self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) @@ -732,32 +733,13 @@ function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... local TaskRoute = self.CargoObject:TaskRoute( Points ) self.CargoObject:SetTask( TaskRoute, 2 ) self:__Boarding( -1, CargoCarrier, NearRadius ) + self.RunCount = 0 end end end ---- Leave Boarding State. --- @param #CARGO_UNIT self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier -function CARGO_UNIT:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - - local NearRadius = NearRadius or 25 - - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:__Load( 1, CargoCarrier, ... ) - return true - end - - return true -end - - --- Boarding Event. -- @param #CARGO_UNIT self -- @param #string Event @@ -769,8 +751,45 @@ function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) - self:__Boarding( -1, CargoCarrier, NearRadius, ... ) - self:__Board( -10, CargoCarrier, NearRadius, ... ) + if CargoCarrier and CargoCarrier:IsAlive() then + if CargoCarrier:InAir() == false then + if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then + self:__Load( 1, CargoCarrier, ... ) + else + self:__Boarding( -1, CargoCarrier, NearRadius, ... ) + self.RunCount = self.RunCount + 1 + if self.RunCount >= 20 then + self.RunCount = 0 + local Speed = 90 + local Angle = 180 + local Distance = 5 + + NearRadius = NearRadius or 25 + + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) + + local Points = {} + + local PointStartVec2 = self.CargoObject:GetPointVec2() + + Points[#Points+1] = PointStartVec2:RoutePointGround( Speed ) + Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 0.2 ) + end + end + else + self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) + self:CancelBoarding( CargoCarrier, NearRadius, ... ) + self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) + end + else + self:E("Something is wrong") + end end @@ -818,6 +837,254 @@ end end + +do -- CARGO_GROUP + + --- @type CARGO_GROUP + -- @extends #CARGO_REPORTABLE + + --- # CARGO\_GROUP class + -- + -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator, and can be transported by a carrier. + -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_GROUP to and from carrier. + -- + -- @field #CARGO_GROUP CARGO_GROUP + -- + CARGO_GROUP = { + ClassName = "CARGO_GROUP", + } + +--- CARGO_GROUP constructor. +-- @param #CARGO_GROUP self +-- @param Wrapper.Group#GROUP CargoGroup +-- @param #string Type +-- @param #string Name +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #CARGO_GROUP +function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, ReportRadius } ) + + self.CargoSet = SET_CARGO:New() + + self.CargoObject = CargoGroup + + local WeightGroup = 0 + + for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do + local Unit = UnitData -- Wrapper.Unit#UNIT + local WeightUnit = Unit:GetDesc().massEmpty + WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) + self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) + end + + self:SetWeight( WeightGroup ) + + self:T( { "Weight Cargo", WeightGroup } ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + return self +end + +--- Enter Boarding State. +-- @param #CARGO_GROUP self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 25 + + if From == "UnLoaded" then + + -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, ... ) + Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) + end, ... + ) + + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + end + +end + +--- Enter Loaded State. +-- @param #CARGO_GROUP self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) + self:F( { From, Event, To, CargoCarrier, ...} ) + + if From == "UnLoaded" then + -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + Cargo:Load( CargoCarrier ) + end + end + + self.CargoObject:Destroy() + self.CargoCarrier = CargoCarrier + +end + +--- Leave Boarding State. +-- @param #CARGO_GROUP self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) + self:F( { CargoCarrier.UnitName, From, Event, To } ) + + local NearRadius = NearRadius or 25 + + local Boarded = true + local Cancelled = false + + self.CargoSet:Flush() + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( { Cargo:GetName(), Cargo.current } ) + if not Cargo:is( "Loaded" ) then + Boarded = false + end + + if Cargo:is( "UnLoaded" ) then + Cancelled = true + end + + + end + + if not Cancelled then + if not Boarded then + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + else + self:__Load( 1, CargoCarrier, ... ) + end + else + self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) + end + +end + +--- Enter UnBoarding State. +-- @param #CARGO_GROUP self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( {From, Event, To, ToPointVec2, NearRadius } ) + + NearRadius = NearRadius or 25 + + local Timer = 1 + + if From == "Loaded" then + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo, NearRadius ) + + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) + Timer = Timer + 10 + end, { NearRadius } + ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + end + +end + +--- Leave UnBoarding State. +-- @param #CARGO_GROUP self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + --local NearRadius = NearRadius or 25 + + local Angle = 180 + local Speed = 10 + local Distance = 5 + + if From == "UnBoarding" then + local UnBoarded = true + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do + self:T( Cargo.current ) + if not Cargo:is( "UnLoaded" ) then + UnBoarded = false + end + end + + if UnBoarded then + return true + else + self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) + end + + return false + end + +end + +--- UnBoard Event. +-- @param #CARGO_GROUP self +-- @param Core.Point#POINT_VEC2 ToPointVec2 +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) + self:F( { From, Event, To, ToPointVec2, NearRadius } ) + + --local NearRadius = NearRadius or 25 + + self:__UnLoad( 1, ToPointVec2, ... ) +end + + + +--- Enter UnLoaded State. +-- @param #CARGO_GROUP self +-- @param Core.Point#POINT_VEC2 +-- @param #string Event +-- @param #string From +-- @param #string To +function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) + self:F( { From, Event, To, ToPointVec2 } ) + + if From == "Loaded" then + + -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 + self.CargoSet:ForEach( + function( Cargo ) + Cargo:UnLoad( ToPointVec2 ) + end + ) + + end + +end + +end -- CARGO_GROUP + do -- CARGO_PACKAGE --- @type CARGO_PACKAGE @@ -1032,240 +1299,3 @@ end end - -do -- CARGO_GROUP - - --- @type CARGO_GROUP - -- @extends #CARGO_REPORTABLE - - --- # CARGO\_GROUP class - -- - -- The CARGO\_GROUP class defines a cargo that is represented by a @{Group} object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_GROUP to and from carrier. - -- - -- @field #CARGO_GROUP CARGO_GROUP - -- - CARGO_GROUP = { - ClassName = "CARGO_GROUP", - } - ---- CARGO_GROUP constructor. --- @param #CARGO_GROUP self --- @param Wrapper.Group#GROUP CargoGroup --- @param #string Type --- @param #string Name --- @param #number ReportRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_GROUP -function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) - - self.CargoSet = SET_CARGO:New() - - self.CargoObject = CargoGroup - - local WeightGroup = 0 - - for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - local WeightUnit = Unit:GetDesc().massEmpty - WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) - self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) - end - - self:SetWeight( WeightGroup ) - - self:T( { "Weight Cargo", WeightGroup } ) - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - return self -end - ---- Enter Boarding State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 25 - - if From == "UnLoaded" then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:__Board( 1, CargoCarrier, NearRadius ) - end - ) - - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - end - -end - ---- Enter Loaded State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - if From == "UnLoaded" then - -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - Cargo:Load( CargoCarrier ) - end - end - - self.CargoObject:Destroy() - self.CargoCarrier = CargoCarrier - -end - ---- Leave Boarding State. --- @param #CARGO_GROUP self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onleaveBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:F( { CargoCarrier.UnitName, From, Event, To } ) - - local NearRadius = NearRadius or 25 - - local Boarded = true - - self.CargoSet:Flush() - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( { Cargo:GetName(), Cargo.current } ) - if not Cargo:is( "Loaded" ) then - Boarded = false - end - end - - if not Boarded then - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) - else - self:__Load( 1, CargoCarrier, ... ) - end - return Boarded -end - ---- Enter UnBoarding State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( {From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 25 - - local Timer = 1 - - if From == "Loaded" then - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, NearRadius ) - - Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 10 - end, { NearRadius } - ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - -end - ---- Leave UnBoarding State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( Cargo.current ) - if not Cargo:is( "UnLoaded" ) then - UnBoarded = false - end - end - - if UnBoarded then - return true - else - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - - return false - end - -end - ---- UnBoard Event. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 ToPointVec2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) - self:F( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - self:__UnLoad( 1, ToPointVec2, ... ) -end - - - ---- Enter UnLoaded State. --- @param #CARGO_GROUP self --- @param Core.Point#POINT_VEC2 --- @param #string Event --- @param #string From --- @param #string To -function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) - self:F( { From, Event, To, ToPointVec2 } ) - - if From == "Loaded" then - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - Cargo:UnLoad( ToPointVec2 ) - end - ) - - end - -end - -end -- CARGO_GROUP - diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 38d5c2316..2cd135bd0 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -277,6 +277,8 @@ do -- TASK_CARGO ) self:__SelectAction( -15 ) + + Task:GetMission():GetCommandCenter():MessageToGroup("Cargo menu is ready ...", TaskUnit:GetGroup() ) end --- @@ -429,14 +431,10 @@ do -- TASK_CARGO self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) function self.Cargo:OnEnterLoaded( From, Event, To, TaskUnit, TaskProcess ) - self:E({From, Event, To, TaskUnit, TaskProcess }) - TaskProcess:__Boarded( 0.1 ) - end - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then if TaskUnit:InAir() then --- ABORT the boarding. Split group if any and go back to select action. From ce1f85e09adebab617e5d97b4dc4f636e3072175 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 8 May 2017 16:28:36 +0200 Subject: [PATCH 12/32] Fixed menu and deployment of cargo -- You can now deploy cargo anywhere in the battlefield. -- The menu generation is improved. ---- No more first remove menu and then build, but "refresh"... --- .../Moose/Tasking/Task_CARGO.lua | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 2cd135bd0..2ee08dc55 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -182,24 +182,24 @@ do -- TASK_CARGO Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } ) - Fsm:AddTransition( { "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Landed" }, "SelectAction", "WaitingForCommand" ) + Fsm:AddTransition( { "Assigned", "WaitingForCommand", "ArrivedAtPickup", "ArrivedAtDeploy", "Boarded", "UnBoarded", "Landed", "Boarding" }, "SelectAction", "*" ) - Fsm:AddTransition( "WaitingForCommand", "RouteToPickup", "RoutingToPickup" ) + Fsm:AddTransition( "*", "RouteToPickup", "RoutingToPickup" ) Fsm:AddProcess ( "RoutingToPickup", "RouteToPickupPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtPickup" } ) Fsm:AddTransition( "Arrived", "ArriveAtPickup", "ArrivedAtPickup" ) - Fsm:AddTransition( "WaitingForCommand", "RouteToDeploy", "RoutingToDeploy" ) + Fsm:AddTransition( "*", "RouteToDeploy", "RoutingToDeploy" ) Fsm:AddProcess ( "RoutingToDeploy", "RouteToDeployZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtDeploy" } ) Fsm:AddTransition( "Arrived", "ArriveAtDeploy", "ArrivedAtDeploy" ) Fsm:AddTransition( { "ArrivedAtPickup", "ArrivedAtDeploy", "Landing" }, "Land", "Landing" ) Fsm:AddTransition( "Landing", "Landed", "Landed" ) - Fsm:AddTransition( "WaitingForCommand", "PrepareBoarding", "AwaitBoarding" ) + Fsm:AddTransition( "*", "PrepareBoarding", "AwaitBoarding" ) Fsm:AddTransition( "AwaitBoarding", "Board", "Boarding" ) Fsm:AddTransition( "Boarding", "Boarded", "Boarded" ) - Fsm:AddTransition( "WaitingForCommand", "PrepareUnBoarding", "AwaitUnBoarding" ) + Fsm:AddTransition( "*", "PrepareUnBoarding", "AwaitUnBoarding" ) Fsm:AddTransition( "AwaitUnBoarding", "UnBoard", "UnBoarding" ) Fsm:AddTransition( "UnBoarding", "UnBoarded", "UnBoarded" ) @@ -213,14 +213,12 @@ do -- TASK_CARGO -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_CARGO#TASK_CARGO Task - function Fsm:onenterWaitingForCommand( TaskUnit, Task ) + function Fsm:onafterSelectAction( TaskUnit, Task ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if TaskUnit.Menu then - TaskUnit.Menu:Remove() - end + local MenuTime = timer.getTime() - TaskUnit.Menu = MENU_GROUP:New( TaskUnit:GetGroup(), Task:GetName() .. " @ " .. TaskUnit:GetName() ) + TaskUnit.Menu = MENU_GROUP:New( TaskUnit:GetGroup(), Task:GetName() .. " @ " .. TaskUnit:GetName() ):SetTime( MenuTime ) Task.SetCargo:ForEachCargo( @@ -235,7 +233,7 @@ do -- TASK_CARGO self.MenuBoardCargo, self, Cargo - ) + ):SetTime(MenuTime) else MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), @@ -244,23 +242,24 @@ do -- TASK_CARGO self.MenuRouteToPickup, self, Cargo - ) + ):SetTime(MenuTime) end end if Cargo:IsLoaded() then + + MENU_GROUP_COMMAND:New( + TaskUnit:GetGroup(), + "Unboard cargo " .. Cargo.Name, + TaskUnit.Menu, + self.MenuUnBoardCargo, + self, + Cargo + ):SetTime(MenuTime) + + -- Deployzones are optional zones that can be selected to request routing information. for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if Cargo:IsInZone( DeployZone ) then - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Unboard cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuUnBoardCargo, - self, - Cargo, - DeployZone - ) - else + if not Cargo:IsInZone( DeployZone ) then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Deploy cargo at " .. DeployZoneName, @@ -268,13 +267,16 @@ do -- TASK_CARGO self.MenuRouteToDeploy, self, DeployZone - ) + ):SetTime(MenuTime) end end end end ) + + TaskUnit.Menu:Remove( MenuTime ) + self:__SelectAction( -15 ) @@ -476,12 +478,20 @@ do -- TASK_CARGO -- @param To -- @param Cargo -- @param Core.Zone#ZONE_BASE DeployZone - function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo, DeployZone ) - self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo, DeployZone } ) + function Fsm:onafterPrepareUnBoarding( TaskUnit, Task, From, Event, To, Cargo ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo } ) self.Cargo = Cargo - self.DeployZone = DeployZone -- Core.Zone#ZONE_BASE - self:__UnBoard( -0.1, Cargo, DeployZone ) + self.DeployZone = nil + + -- Check if the Cargo is at a deployzone... If it is, provide it as a parameter! + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if Cargo:IsInZone( DeployZone ) then + self.DeployZone = DeployZone -- Core.Zone#ZONE_BASE + break + end + end + self:__UnBoard( -0.1, Cargo, self.DeployZone ) end --- From d8ba37af8d0ed60b90a654ced38c38c9a489fe93 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 9 May 2017 09:29:08 +0200 Subject: [PATCH 13/32] When cargo is destroyed, it will stop working... --- Moose Development/Moose/Core/Cargo.lua | 59 ++++- .../Moose/Tasking/Task_CARGO.lua | 209 ++++++++++-------- 2 files changed, 170 insertions(+), 98 deletions(-) diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 281d81224..88635422f 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -246,6 +246,8 @@ function CARGO:New( Type, Name, Weight ) --R2.1 self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) + self:AddTransition( "*", "Destroyed", "Destroyed" ) + self:AddTransition( "*", "Respawn", "UnLoaded" ) self.Type = Type @@ -263,6 +265,7 @@ function CARGO:New( Type, Name, Weight ) --R2.1 CARGOS[self.Name] = self self:SetEventPriority( 5 ) + return self end @@ -274,6 +277,17 @@ function CARGO:GetName() --R2.1 return self.Name end +--- Get the object name of the Cargo. +-- @param #CARGO self +-- @return #string The object name of the Cargo. +function CARGO:GetObjectName() --R2.1 + if self:IsLoaded() then + return self.CargoCarrier:GetName() + else + return self.CargoObject:GetName() + end +end + --- Get the type of the Cargo. -- @param #CARGO self -- @return #string The type of the Cargo. @@ -303,6 +317,20 @@ function CARGO:IsUnLoaded() return self:Is( "UnLoaded" ) end +--- Check if cargo is alive. +-- @param #CARGO self +-- @return #boolean true if unloaded +function CARGO:IsAlive() + + if self:IsLoaded() then + return self.CargoCarrier:IsAlive() + else + return self.CargoObject:IsAlive() + end +end + + + --- Template method to spawn a new representation of the CARGO in the simulator. -- @param #CARGO self @@ -529,6 +557,16 @@ function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) self:T( self.ClassName ) + self:HandleEvent( EVENTS.Dead, + --- @param #CARGO Cargo + -- @param Core.Event#EVENTDATA EventData + function( Cargo, EventData ) + if Cargo:GetObjectName() == EventData.IniUnit:GetName() then + self:E( { "Cargo destroyed", Cargo } ) + Cargo:Destroyed() + end + end + ) return self end @@ -949,6 +987,7 @@ function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, local Boarded = true local Cancelled = false + local Dead = true self.CargoSet:Flush() @@ -962,18 +1001,26 @@ function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, if Cargo:is( "UnLoaded" ) then Cancelled = true end - + + if not Cargo:is( "Destroyed" ) then + Dead = false + end end - if not Cancelled then - if not Boarded then - self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + if not Dead then + + if not Cancelled then + if not Boarded then + self:__Boarding( 1, CargoCarrier, NearRadius, ... ) + else + self:__Load( 1, CargoCarrier, ... ) + end else - self:__Load( 1, CargoCarrier, ... ) + self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) end else - self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) + self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) end end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 2ee08dc55..776fe499b 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -224,50 +224,54 @@ do -- TASK_CARGO --- @param Core.Cargo#CARGO Cargo function( Cargo ) - if Cargo:IsUnLoaded() then - if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Board cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuBoardCargo, - self, - Cargo - ):SetTime(MenuTime) - else - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Route to Pickup cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuRouteToPickup, - self, - Cargo - ):SetTime(MenuTime) - end - end - - if Cargo:IsLoaded() then - - MENU_GROUP_COMMAND:New( - TaskUnit:GetGroup(), - "Unboard cargo " .. Cargo.Name, - TaskUnit.Menu, - self.MenuUnBoardCargo, - self, - Cargo - ):SetTime(MenuTime) - - -- Deployzones are optional zones that can be selected to request routing information. - for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if not Cargo:IsInZone( DeployZone ) then + + if Cargo:IsAlive() then + + if Cargo:IsUnLoaded() then + if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), - "Route to Deploy cargo at " .. DeployZoneName, + "Board cargo " .. Cargo.Name, TaskUnit.Menu, - self.MenuRouteToDeploy, + self.MenuBoardCargo, self, - DeployZone + Cargo ):SetTime(MenuTime) + else + MENU_GROUP_COMMAND:New( + TaskUnit:GetGroup(), + "Route to Pickup cargo " .. Cargo.Name, + TaskUnit.Menu, + self.MenuRouteToPickup, + self, + Cargo + ):SetTime(MenuTime) + end + end + + if Cargo:IsLoaded() then + + MENU_GROUP_COMMAND:New( + TaskUnit:GetGroup(), + "Unboard cargo " .. Cargo.Name, + TaskUnit.Menu, + self.MenuUnBoardCargo, + self, + Cargo + ):SetTime(MenuTime) + + -- Deployzones are optional zones that can be selected to request routing information. + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if not Cargo:IsInZone( DeployZone ) then + MENU_GROUP_COMMAND:New( + TaskUnit:GetGroup(), + "Route to Deploy cargo at " .. DeployZoneName, + TaskUnit.Menu, + self.MenuRouteToDeploy, + self, + DeployZone + ):SetTime(MenuTime) + end end end end @@ -313,13 +317,19 @@ do -- TASK_CARGO -- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit -- @param Tasking.Task_Cargo#TASK_CARGO Task + -- @param From + -- @param Event + -- @param To + -- @param Core.Cargo#CARGO Cargo function Fsm:onafterRouteToPickup( TaskUnit, Task, From, Event, To, Cargo ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + if Cargo:IsAlive() then + self.Cargo = Cargo -- Core.Cargo#CARGO + Task:SetCargoPickup( self.Cargo, TaskUnit ) + self:__RouteToPickupPoint( -0.1 ) + end - self.Cargo = Cargo -- Core.Cargo#CARGO - Task:SetCargoPickup( self.Cargo, TaskUnit ) - self:__RouteToPickupPoint( -0.1 ) end @@ -330,11 +340,13 @@ do -- TASK_CARGO function Fsm:onafterArriveAtPickup( TaskUnit, Task ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if TaskUnit:IsAir() then - self.Cargo.CargoObject:GetUnit(1):SmokeRed() - self:__Land( -0.1, "Pickup" ) - else - self:__SelectAction( -0.1 ) + if self.Cargo:IsAlive() then + if TaskUnit:IsAir() then + self.Cargo.CargoObject:GetUnit(1):SmokeRed() + self:__Land( -0.1, "Pickup" ) + else + self:__SelectAction( -0.1 ) + end end end @@ -375,19 +387,21 @@ do -- TASK_CARGO function Fsm:onafterLand( TaskUnit, Task, From, Event, To, Action ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then - if TaskUnit:InAir() then - Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) - self:__Land( -10, Action ) + if self.Cargo:IsAlive() then + if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if TaskUnit:InAir() then + Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() ) + self:__Land( -10, Action ) + else + Task:GetMission():GetCommandCenter():MessageToGroup( "Landed ...", TaskUnit:GetGroup() ) + self:__Landed( -0.1, Action ) + end else - Task:GetMission():GetCommandCenter():MessageToGroup( "Landed ...", TaskUnit:GetGroup() ) - self:__Landed( -0.1, Action ) - end - else - if Action == "Pickup" then - self:__RouteToPickupZone( -0.1 ) - else - self:__RouteToDeployZone( -0.1 ) + if Action == "Pickup" then + self:__RouteToPickupZone( -0.1 ) + else + self:__RouteToDeployZone( -0.1 ) + end end end end @@ -399,17 +413,19 @@ do -- TASK_CARGO function Fsm:onafterLanded( TaskUnit, Task, From, Event, To, Action ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then - if TaskUnit:InAir() then - self:__Land( -0.1, Action ) + if self.Cargo:IsAlive() then + if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if TaskUnit:InAir() then + self:__Land( -0.1, Action ) + else + self:__SelectAction( -0.1 ) + end else - self:__SelectAction( -0.1 ) - end - else - if Action == "Pickup" then - self:__RouteToPickupZone( -0.1 ) - else - self:__RouteToDeployZone( -0.1 ) + if Action == "Pickup" then + self:__RouteToPickupZone( -0.1 ) + else + self:__RouteToDeployZone( -0.1 ) + end end end end @@ -421,8 +437,10 @@ do -- TASK_CARGO function Fsm:onafterPrepareBoarding( TaskUnit, Task, From, Event, To, Cargo ) self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) - self.Cargo = Cargo -- Core.Cargo#CARGO_GROUP - self:__Board( -0.1 ) + if Cargo and Cargo:IsAlive() then + self.Cargo = Cargo -- Core.Cargo#CARGO_GROUP + self:__Board( -0.1 ) + end end --- @@ -437,15 +455,17 @@ do -- TASK_CARGO TaskProcess:__Boarded( 0.1 ) end - if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then - if TaskUnit:InAir() then - --- ABORT the boarding. Split group if any and go back to select action. + if self.Cargo:IsAlive() then + if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then + if TaskUnit:InAir() then + --- ABORT the boarding. Split group if any and go back to select action. + else + self.Cargo:MessageToGroup( "Boarding ...", TaskUnit:GetGroup() ) + self.Cargo:Board( TaskUnit, 20, self ) + end else - self.Cargo:MessageToGroup( "Boarding ...", TaskUnit:GetGroup() ) - self.Cargo:Board( TaskUnit, 20, self ) + --self:__ArriveAtCargo( -0.1 ) end - else - --self:__ArriveAtCargo( -0.1 ) end end @@ -462,8 +482,10 @@ do -- TASK_CARGO -- TODO:I need to find a more decent solution for this. Task:E( { CargoPickedUp = Task.CargoPickedUp } ) - if Task.CargoPickedUp then - Task:CargoPickedUp( TaskUnit, self.Cargo ) + if self.Cargo:IsAlive() then + if Task.CargoPickedUp then + Task:CargoPickedUp( TaskUnit, self.Cargo ) + end end end @@ -485,13 +507,15 @@ do -- TASK_CARGO self.DeployZone = nil -- Check if the Cargo is at a deployzone... If it is, provide it as a parameter! - for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do - if Cargo:IsInZone( DeployZone ) then - self.DeployZone = DeployZone -- Core.Zone#ZONE_BASE - break + if Cargo:IsAlive() then + for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do + if Cargo:IsInZone( DeployZone ) then + self.DeployZone = DeployZone -- Core.Zone#ZONE_BASE + break + end end + self:__UnBoard( -0.1, Cargo, self.DeployZone ) end - self:__UnBoard( -0.1, Cargo, self.DeployZone ) end --- @@ -507,15 +531,14 @@ do -- TASK_CARGO self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID(), From, Event, To, Cargo, DeployZone } ) function self.Cargo:OnEnterUnLoaded( From, Event, To, DeployZone, TaskProcess ) - self:E({From, Event, To, DeployZone, TaskProcess }) - TaskProcess:__UnBoarded( -0.1 ) - end - self.Cargo:MessageToGroup( "UnBoarding ...", TaskUnit:GetGroup() ) - self.Cargo:UnBoard( DeployZone:GetPointVec2(), 400, self ) + if self.Cargo:IsAlive() then + self.Cargo:MessageToGroup( "UnBoarding ...", TaskUnit:GetGroup() ) + self.Cargo:UnBoard( DeployZone:GetPointVec2(), 400, self ) + end end @@ -530,8 +553,10 @@ do -- TASK_CARGO -- TODO:I need to find a more decent solution for this. Task:E( { CargoDeployed = Task.CargoDeployed } ) - if Task.CargoDeployed then - Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone ) + if self.Cargo:IsAlive() then + if Task.CargoDeployed then + Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone ) + end end self:__SelectAction( 1 ) From 743fa8ced1f3255b3a5148fc5baf724c22bcab5b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 9 May 2017 10:40:05 +0200 Subject: [PATCH 14/32] new AI_BAI class --- .../Moose/AI/{AI_Bomb.lua => AI_BAI.lua} | 249 +-- .../Moose/Wrapper/Controllable.lua | 26 +- Moose Mission Setup/Moose.files | 1 + Moose Mission Setup/Moose.lua | 3 +- .../bin/TreeHierarchy.csv | 38 +- docs/Documentation/AI_BAI.html | 1875 +++++++++++++++++ docs/Documentation/AI_Balancer.html | 1 + docs/Documentation/AI_Cap.html | 1 + docs/Documentation/AI_Cas.html | 1 + docs/Documentation/AI_Patrol.html | 1 + docs/Documentation/Account.html | 1 + docs/Documentation/Airbase.html | 1 + docs/Documentation/AirbasePolice.html | 1 + docs/Documentation/Assign.html | 1 + docs/Documentation/Base.html | 1 + docs/Documentation/Cargo.html | 250 ++- docs/Documentation/CleanUp.html | 1 + docs/Documentation/Client.html | 1 + docs/Documentation/CommandCenter.html | 37 +- docs/Documentation/Controllable.html | 13 +- docs/Documentation/DCSAirbase.html | 1 + docs/Documentation/DCSCoalitionObject.html | 1 + docs/Documentation/DCSCommand.html | 1 + docs/Documentation/DCSController.html | 1 + docs/Documentation/DCSGroup.html | 1 + docs/Documentation/DCSObject.html | 1 + docs/Documentation/DCSTask.html | 1 + docs/Documentation/DCSTypes.html | 1 + docs/Documentation/DCSUnit.html | 1 + docs/Documentation/DCSVec3.html | 1 + docs/Documentation/DCSWorld.html | 1 + docs/Documentation/DCSZone.html | 1 + docs/Documentation/DCScountry.html | 1 + docs/Documentation/DCStimer.html | 1 + docs/Documentation/DCStrigger.html | 1 + docs/Documentation/Database.html | 40 + docs/Documentation/Designate.html | 2 +- docs/Documentation/Detection.html | 2 +- docs/Documentation/DetectionManager.html | 1 + docs/Documentation/Escort.html | 1 + docs/Documentation/Event.html | 28 + docs/Documentation/Fsm.html | 4 +- docs/Documentation/Group.html | 1 + docs/Documentation/Identifiable.html | 1 + docs/Documentation/Menu.html | 1 + docs/Documentation/Message.html | 1 + docs/Documentation/MissileTrainer.html | 1 + docs/Documentation/Mission.html | 222 +- docs/Documentation/Movement.html | 1 + docs/Documentation/Object.html | 1 + docs/Documentation/Point.html | 2 + docs/Documentation/Positionable.html | 11 +- docs/Documentation/Process_JTAC.html | 1 + docs/Documentation/Process_Pickup.html | 1 + docs/Documentation/Radio.html | 1 + docs/Documentation/Route.html | 1 + docs/Documentation/Scenery.html | 1 + docs/Documentation/ScheduleDispatcher.html | 1 + docs/Documentation/Scheduler.html | 1 + docs/Documentation/Scoring.html | 1 + docs/Documentation/Sead.html | 1 + docs/Documentation/Set.html | 25 + docs/Documentation/Smoke.html | 1 + docs/Documentation/Spawn.html | 11 +- docs/Documentation/SpawnStatic.html | 2 +- docs/Documentation/Spot.html | 5 + docs/Documentation/Static.html | 1 + docs/Documentation/StaticObject.html | 1 + docs/Documentation/Task.html | 286 ++- docs/Documentation/Task_A2G.html | 72 +- docs/Documentation/Task_A2G_Dispatcher.html | 1 + docs/Documentation/Task_Cargo.html | 411 +++- docs/Documentation/Task_PICKUP.html | 1 + docs/Documentation/Unit.html | 1 + docs/Documentation/Utils.html | 1 + docs/Documentation/Zone.html | 1 + docs/Documentation/env.html | 1 + docs/Documentation/index.html | 13 + docs/Documentation/land.html | 1 + docs/Documentation/routines.html | 1 + docs/Presentations/AI_BAI/Dia1.JPG | Bin 0 -> 198875 bytes docs/Presentations/AI_BAI/Dia10.JPG | Bin 0 -> 208373 bytes docs/Presentations/AI_BAI/Dia11.JPG | Bin 0 -> 189472 bytes docs/Presentations/AI_BAI/Dia12.JPG | Bin 0 -> 194526 bytes docs/Presentations/AI_BAI/Dia13.JPG | Bin 0 -> 194150 bytes docs/Presentations/AI_BAI/Dia2.JPG | Bin 0 -> 199665 bytes docs/Presentations/AI_BAI/Dia3.JPG | Bin 0 -> 212452 bytes docs/Presentations/AI_BAI/Dia4.JPG | Bin 0 -> 186635 bytes docs/Presentations/AI_BAI/Dia5.JPG | Bin 0 -> 197456 bytes docs/Presentations/AI_BAI/Dia6.JPG | Bin 0 -> 209058 bytes docs/Presentations/AI_BAI/Dia7.JPG | Bin 0 -> 199418 bytes docs/Presentations/AI_BAI/Dia8.JPG | Bin 0 -> 192914 bytes docs/Presentations/AI_BAI/Dia9.JPG | Bin 0 -> 197322 bytes 93 files changed, 3295 insertions(+), 388 deletions(-) rename Moose Development/Moose/AI/{AI_Bomb.lua => AI_BAI.lua} (74%) create mode 100644 docs/Documentation/AI_BAI.html create mode 100644 docs/Presentations/AI_BAI/Dia1.JPG create mode 100644 docs/Presentations/AI_BAI/Dia10.JPG create mode 100644 docs/Presentations/AI_BAI/Dia11.JPG create mode 100644 docs/Presentations/AI_BAI/Dia12.JPG create mode 100644 docs/Presentations/AI_BAI/Dia13.JPG create mode 100644 docs/Presentations/AI_BAI/Dia2.JPG create mode 100644 docs/Presentations/AI_BAI/Dia3.JPG create mode 100644 docs/Presentations/AI_BAI/Dia4.JPG create mode 100644 docs/Presentations/AI_BAI/Dia5.JPG create mode 100644 docs/Presentations/AI_BAI/Dia6.JPG create mode 100644 docs/Presentations/AI_BAI/Dia7.JPG create mode 100644 docs/Presentations/AI_BAI/Dia8.JPG create mode 100644 docs/Presentations/AI_BAI/Dia9.JPG diff --git a/Moose Development/Moose/AI/AI_Bomb.lua b/Moose Development/Moose/AI/AI_BAI.lua similarity index 74% rename from Moose Development/Moose/AI/AI_Bomb.lua rename to Moose Development/Moose/AI/AI_BAI.lua index 406874ed1..4a973eaca 100644 --- a/Moose Development/Moose/AI/AI_Bomb.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -1,22 +1,22 @@ ---- **AI** -- **Provide Close Air Support to friendly ground troops.** +--- **AI** -- **Provide Battleground Air Interdiction (bombing).** -- --- ![Banner Image](..\Presentations\AI_BOMB\Dia1.JPG) +-- ![Banner Image](..\Presentations\AI_BAI\Dia1.JPG) -- -- === -- --- AI_BOMB classes makes AI Controllables execute bombing tasks. +-- AI_BAI classes makes AI Controllables execute bombing tasks. -- --- There are the following types of BOMB classes defined: +-- There are the following types of BAI classes defined: -- --- * @{#AI_BOMB_ZONE}: Perform a BOMB in a zone. +-- * @{#AI_BAI_ZONE}: Perform a BAI in a zone. -- -- ==== -- -- # Demo Missions -- --- ### [AI_BOMB Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support) +-- ### [AI_BAI Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support) -- --- ### [AI_BOMB Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support) +-- ### [AI_BAI Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support) -- -- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) -- @@ -24,7 +24,7 @@ -- -- # YouTube Channel -- --- ### [AI_BOMB YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2) +-- ### [AI_BAI YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2) -- -- === -- @@ -51,51 +51,51 @@ -- -- * **FlightControl**: Concept, Design & Programming. -- --- @module AI_Cas +-- @module AI_BAI ---- AI_BOMB_ZONE class --- @type AI_BOMB_ZONE +--- AI_BAI_ZONE class +-- @type AI_BAI_ZONE -- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. -- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. -- @extends AI.AI_Patrol#AI_PATROL_ZONE ---- # AI_BOMB_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE} +--- # AI_BAI_ZONE class, extends @{AI_Patrol#AI_PATROL_ZONE} -- --- AI_BOMB_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. +-- AI_BAI_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour. -- --- The AI_BOMB_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. --- The AI_BOMB_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. +-- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Controllable} or @{Group}. +-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- --- ![HoldAndEngage](..\Presentations\AI_BOMB\Dia3.JPG) +-- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG) -- --- The AI_BOMB_ZONE is assigned a @{Group} and this must be done before the AI_BOMB_ZONE process can be started through the **Start** event. +-- The AI_BAI_ZONE is assigned a @{Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event. -- --- ![Start Event](..\Presentations\AI_BOMB\Dia4.JPG) +-- ![Start Event](..\Presentations\AI_BAI\Dia4.JPG) -- -- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone, -- using a random speed within the given altitude and speed limits. -- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. -- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB. -- --- ![Route Event](..\Presentations\AI_BOMB\Dia5.JPG) +-- ![Route Event](..\Presentations\AI_BAI\Dia5.JPG) -- --- When the AI is commanded to provide Close Air Support (through the event **Engage**), the AI will fly towards the Engage Zone. +-- When the AI is commanded to provide BattleGround Air Interdiction (through the event **Engage**), the AI will fly towards the Engage Zone. -- Any target that is detected in the Engage Zone will be reported and will be destroyed by the AI. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia6.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia6.JPG) -- -- The AI will detect the targets and will only destroy the targets within the Engage Zone. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia7.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia7.JPG) -- -- Every target that is destroyed, is reported< by the AI. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia8.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia8.JPG) -- -- Note that the AI does not know when the Engage Zone is cleared, and therefore will keep circling in the zone. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia9.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia9.JPG) -- -- Until it is notified through the event **Accomplish**, which is to be triggered by an observing party: -- @@ -105,58 +105,58 @@ -- * a condition -- * others ... -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia10.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia10.JPG) -- --- When the AI has accomplished the BOMB, it will fly back to the Patrol Zone. +-- When the AI has accomplished the Bombing, it will fly back to the Patrol Zone. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia11.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia11.JPG) -- -- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone. -- It can be notified to go RTB through the **RTB** event. -- -- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land. -- --- ![Engage Event](..\Presentations\AI_BOMB\Dia12.JPG) +-- ![Engage Event](..\Presentations\AI_BAI\Dia12.JPG) -- --- # 1. AI_BOMB_ZONE constructor +-- # 1. AI_BAI_ZONE constructor -- --- * @{#AI_BOMB_ZONE.New}(): Creates a new AI_BOMB_ZONE object. +-- * @{#AI_BAI_ZONE.New}(): Creates a new AI_BAI_ZONE object. -- --- ## 2. AI_BOMB_ZONE is a FSM +-- ## 2. AI_BAI_ZONE is a FSM -- --- ![Process](..\Presentations\AI_BOMB\Dia2.JPG) +-- ![Process](..\Presentations\AI_BAI\Dia2.JPG) -- --- ### 2.1. AI_BOMB_ZONE States +-- ### 2.1. AI_BAI_ZONE States -- -- * **None** ( Group ): The process is not started yet. -- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. -- * **Engaging** ( Group ): The AI is engaging the targets in the Engage Zone, executing BOMB. -- * **Returning** ( Group ): The AI is returning to Base.. -- --- ### 2.2. AI_BOMB_ZONE Events +-- ### 2.2. AI_BAI_ZONE Events -- -- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. -- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. --- * **@{#AI_BOMB_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds. --- * **@{#AI_BOMB_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{#AI_BAI_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds. +-- * **@{#AI_BAI_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. -- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_BOMB_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. --- * **@{#AI_BOMB_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task. +-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Unit}. +-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task. -- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- === -- --- @field #AI_BOMB_ZONE -AI_BOMB_ZONE = { - ClassName = "AI_BOMB_ZONE", +-- @field #AI_BAI_ZONE +AI_BAI_ZONE = { + ClassName = "AI_BAI_ZONE", } ---- Creates a new AI_BOMB_ZONE object --- @param #AI_BOMB_ZONE self +--- Creates a new AI_BAI_ZONE object +-- @param #AI_BAI_ZONE self -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. @@ -164,22 +164,22 @@ AI_BOMB_ZONE = { -- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. -- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen. -- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO --- @return #AI_BOMB_ZONE self -function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) +-- @return #AI_BAI_ZONE self +function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType ) -- Inherits from BASE - local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_BOMB_ZONE + local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_BAI_ZONE self.EngageZone = EngageZone self.Accomplished = false self:SetDetectionZone( self.EngageZone ) - self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. --- OnBefore Transition Handler for Event Engage. - -- @function [parent=#AI_BOMB_ZONE] OnBeforeEngage - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnBeforeEngage + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -188,16 +188,16 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Engage. - -- @function [parent=#AI_BOMB_ZONE] OnAfterEngage - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnAfterEngage + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Engage. - -- @function [parent=#AI_BOMB_ZONE] Engage - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] Engage + -- @param #AI_BAI_ZONE self -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. @@ -207,8 +207,8 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @param Dcs.DCSTypes#Azimuth EngageDirection (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. --- Asynchronous Event Trigger for Event Engage. - -- @function [parent=#AI_BOMB_ZONE] __Engage - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] __Engage + -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. -- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone. -- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement. @@ -219,8 +219,8 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @param Dcs.DCSTypes#Azimuth EngageDirection (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. --- OnLeave Transition Handler for State Engaging. --- @function [parent=#AI_BOMB_ZONE] OnLeaveEngaging --- @param #AI_BOMB_ZONE self +-- @function [parent=#AI_BAI_ZONE] OnLeaveEngaging +-- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -228,20 +228,20 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnEnter Transition Handler for State Engaging. --- @function [parent=#AI_BOMB_ZONE] OnEnterEngaging --- @param #AI_BOMB_ZONE self +-- @function [parent=#AI_BAI_ZONE] OnEnterEngaging +-- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - self:AddTransition( "Engaging", "Target", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( "Engaging", "Target", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. - self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. --- OnBefore Transition Handler for Event Fired. - -- @function [parent=#AI_BOMB_ZONE] OnBeforeFired - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnBeforeFired + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -249,27 +249,27 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Fired. - -- @function [parent=#AI_BOMB_ZONE] OnAfterFired - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnAfterFired + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Fired. - -- @function [parent=#AI_BOMB_ZONE] Fired - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] Fired + -- @param #AI_BAI_ZONE self --- Asynchronous Event Trigger for Event Fired. - -- @function [parent=#AI_BOMB_ZONE] __Fired - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] __Fired + -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. - self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. --- OnBefore Transition Handler for Event Destroy. - -- @function [parent=#AI_BOMB_ZONE] OnBeforeDestroy - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnBeforeDestroy + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -277,28 +277,28 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Destroy. - -- @function [parent=#AI_BOMB_ZONE] OnAfterDestroy - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnAfterDestroy + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_BOMB_ZONE] Destroy - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] Destroy + -- @param #AI_BAI_ZONE self --- Asynchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_BOMB_ZONE] __Destroy - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] __Destroy + -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. - self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. --- OnBefore Transition Handler for Event Abort. - -- @function [parent=#AI_BOMB_ZONE] OnBeforeAbort - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnBeforeAbort + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -306,27 +306,27 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Abort. - -- @function [parent=#AI_BOMB_ZONE] OnAfterAbort - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnAfterAbort + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Abort. - -- @function [parent=#AI_BOMB_ZONE] Abort - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] Abort + -- @param #AI_BAI_ZONE self --- Asynchronous Event Trigger for Event Abort. - -- @function [parent=#AI_BOMB_ZONE] __Abort - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] __Abort + -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. - self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BOMB_ZONE. + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_BAI_ZONE. --- OnBefore Transition Handler for Event Accomplish. - -- @function [parent=#AI_BOMB_ZONE] OnBeforeAccomplish - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnBeforeAccomplish + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -334,20 +334,20 @@ function AI_BOMB_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitud -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Accomplish. - -- @function [parent=#AI_BOMB_ZONE] OnAfterAccomplish - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] OnAfterAccomplish + -- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_BOMB_ZONE] Accomplish - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] Accomplish + -- @param #AI_BAI_ZONE self --- Asynchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_BOMB_ZONE] __Accomplish - -- @param #AI_BOMB_ZONE self + -- @function [parent=#AI_BAI_ZONE] __Accomplish + -- @param #AI_BAI_ZONE self -- @param #number Delay The delay in seconds. return self @@ -355,10 +355,10 @@ end --- Set the Engage Zone where the AI is performing BOMB. Note that if the EngageZone is changed, the AI needs to re-detect targets. --- @param #AI_BOMB_ZONE self +-- @param #AI_BAI_ZONE self -- @param Core.Zone#ZONE EngageZone The zone where the AI is performing BOMB. --- @return #AI_BOMB_ZONE self -function AI_BOMB_ZONE:SetEngageZone( EngageZone ) +-- @return #AI_BAI_ZONE self +function AI_BAI_ZONE:SetEngageZone( EngageZone ) self:F2() if EngageZone then @@ -371,12 +371,12 @@ end --- onafter State Transition for Event Start. --- @param #AI_BOMB_ZONE self +-- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_BOMB_ZONE:onafterStart( Controllable, From, Event, To ) +function AI_BAI_ZONE:onafterStart( Controllable, From, Event, To ) -- Call the parent Start event handler self:GetParent(self).onafterStart( self, Controllable, From, Event, To ) @@ -389,29 +389,29 @@ end function _NewEngageRoute( AIControllable ) AIControllable:T( "NewEngageRoute" ) - local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_BOMB_ZONE + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_BAI#AI_BAI_ZONE EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection ) end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_BOMB_ZONE:onbeforeEngage( Controllable, From, Event, To ) +function AI_BAI_ZONE:onbeforeEngage( Controllable, From, Event, To ) if self.Accomplished == true then return false end end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_BOMB_ZONE:onafterTarget( Controllable, From, Event, To ) +function AI_BAI_ZONE:onafterTarget( Controllable, From, Event, To ) self:E("onafterTarget") if Controllable:IsAlive() then @@ -440,17 +440,17 @@ function AI_BOMB_ZONE:onafterTarget( Controllable, From, Event, To ) end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_BOMB_ZONE:onafterAbort( Controllable, From, Event, To ) +function AI_BAI_ZONE:onafterAbort( Controllable, From, Event, To ) Controllable:ClearTasks() self:__Route( 1 ) end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -460,7 +460,7 @@ end -- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (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 EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo. -- @param Dcs.DCSTypes#Azimuth EngageDirection (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. -function AI_BOMB_ZONE:onafterEngage( Controllable, From, Event, To, +function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To, EngageSpeed, EngageAltitude, EngageWeaponExpend, @@ -497,18 +497,19 @@ function AI_BOMB_ZONE:onafterEngage( Controllable, From, Event, To, local AttackTasks = {} - for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do - local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + for DetectedUnitID, DetectedUnitData in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnitData -- Wrapper.Unit#UNIT self:T( DetectedUnit ) if DetectedUnit:IsAlive() then if DetectedUnit:IsInZone( self.EngageZone ) then self:E( {"Engaging ", DetectedUnit } ) - AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit, - true, - EngageWeaponExpend, - EngageAttackQty, - EngageDirection - ) + AttackTasks[#AttackTasks+1] = Controllable:TaskBombing( + DetectedUnit:GetPointVec2():GetVec2(), + true, + EngageWeaponExpend, + EngageAttackQty, + EngageDirection + ) end else self.DetectedUnits[DetectedUnit] = nil @@ -558,24 +559,24 @@ function AI_BOMB_ZONE:onafterEngage( Controllable, From, Event, To, end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_BOMB_ZONE:onafterAccomplish( Controllable, From, Event, To ) +function AI_BAI_ZONE:onafterAccomplish( Controllable, From, Event, To ) self.Accomplished = true self:SetDetectionDeactivated() end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -- @param Core.Event#EVENTDATA EventData -function AI_BOMB_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) +function AI_BAI_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) if EventData.IniUnit then self.DetectedUnits[EventData.IniUnit] = nil @@ -583,9 +584,9 @@ function AI_BOMB_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) end ---- @param #AI_BOMB_ZONE self +--- @param #AI_BAI_ZONE self -- @param Core.Event#EVENTDATA EventData -function AI_BOMB_ZONE:OnEventDead( EventData ) +function AI_BAI_ZONE:OnEventDead( EventData ) self:F( { "EventDead", EventData } ) if EventData.IniDCSUnit then diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index ec62872f1..a1c038a40 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -585,14 +585,14 @@ end --- (AIR) Delivering weapon at the point on the ground. -- @param #CONTROLLABLE self -- @param Dcs.DCSTypes#Vec2 Vec2 2D-coordinates of the point to deliver weapon at. --- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. +-- @param #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. -- @param Dcs.DCSTypes#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion. -- @param #number AttackQty (optional) Desired quantity of passes. The parameter is not the same in AttackGroup and AttackUnit tasks. -- @param Dcs.DCSTypes#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction. --- @param #boolean ControllableAttack (optional) Flag indicates that the target must be engaged by all aircrafts of the controllable. Has effect only if the task is assigned to a controllable, not to a single aircraft. +-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage. -- @return Dcs.DCSTasking.Task#Task The DCS task structure. -function CONTROLLABLE:TaskBombing( Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack ) - self:F2( { self.ControllableName, Vec2, WeaponType, WeaponExpend, AttackQty, Direction, ControllableAttack } ) +function CONTROLLABLE:TaskBombing( Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, WeaponType ) + self:F2( { self.ControllableName, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, WeaponType } ) -- Bombing = { -- id = 'Bombing', @@ -607,15 +607,17 @@ function CONTROLLABLE:TaskBombing( Vec2, WeaponType, WeaponExpend, AttackQty, Di -- } local DCSTask - DCSTask = { id = 'Bombing', + DCSTask = { + id = 'Bombing', params = { - point = Vec2, - weaponType = WeaponType, - expend = WeaponExpend, - attackQty = AttackQty, - direction = Direction, - controllableAttack = ControllableAttack, - }, + point = Vec2, + groupAttack = GroupAttack, + expend = WeaponExpend or "Auto", + attackQty = AttackQty, + directionEnabled = Direction and true or false, + direction = Direction, + weaponType = WeaponType, + }, }, self:T3( { DCSTask } ) diff --git a/Moose Mission Setup/Moose.files b/Moose Mission Setup/Moose.files index 2de1eb7b3..6cc1565c1 100644 --- a/Moose Mission Setup/Moose.files +++ b/Moose Mission Setup/Moose.files @@ -43,6 +43,7 @@ AI/AI_Balancer.lua AI/AI_Patrol.lua AI/AI_Cap.lua AI/AI_Cas.lua +AI/AI_Bai.lua Actions/Act_Assign.lua Actions/Act_Route.lua diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index c384faa86..0e752810b 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170426_1017' ) +env.info( 'Moose Generation Timestamp: 20170509_1016' ) local base = _G @@ -62,6 +62,7 @@ __Moose.Include( 'AI/AI_Balancer.lua' ) __Moose.Include( 'AI/AI_Patrol.lua' ) __Moose.Include( 'AI/AI_Cap.lua' ) __Moose.Include( 'AI/AI_Cas.lua' ) +__Moose.Include( 'AI/AI_Bai.lua' ) __Moose.Include( 'Actions/Act_Assign.lua' ) __Moose.Include( 'Actions/Act_Route.lua' ) __Moose.Include( 'Actions/Act_Account.lua' ) diff --git a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv index 41eb85a6a..11299e7e5 100644 --- a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv +++ b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv @@ -1,22 +1,22 @@ -@K=function, @M=Task_A2G, @N=onafterRouteToRendezVous, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=5129, -@K=function, @M=Task_A2G, @N=OnAfterArriveAtRendezVous, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=5789, -@K=function, @M=Task_A2G, @N=onafterEngage, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=6186, -@K=function, @M=Task_A2G, @N=onafterRouteToTarget, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=6508, -@K=function, @M=Task_A2G, @N=onafterRouteToTargets, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=7380, -@K=function, @M=Task_Cargo, @N=onenterWaitingForCommand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=10431, -@K=function, @M=Task_Cargo, @N=OnLeaveWaitingForCommand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=12652, -@K=function, @M=Task_Cargo, @N=onafterRouteToPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13428, -@K=function, @M=Task_Cargo, @N=onafterArriveAtPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13882, -@K=function, @M=Task_Cargo, @N=onafterRouteToDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=14310, -@K=function, @M=Task_Cargo, @N=onafterArriveAtDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=14757, -@K=function, @M=Task_Cargo, @N=onafterLand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15187, -@K=function, @M=Task_Cargo, @N=onafterLanded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=16069, -@K=function, @M=Task_Cargo, @N=onafterPrepareBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=16762, -@K=function, @M=Task_Cargo, @N=onafterBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=17166, -@K=function, @M=Task_Cargo, @N=onafterBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=18074, -@K=function, @M=Task_Cargo, @N=onafterPrepareUnBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=18704, -@K=function, @M=Task_Cargo, @N=onafterUnBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19134, -@K=function, @M=Task_Cargo, @N=onafterUnBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19788, +@K=function, @M=Task_A2G, @N=onafterRouteToRendezVous, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=5157, +@K=function, @M=Task_A2G, @N=OnAfterArriveAtRendezVous, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=5817, +@K=function, @M=Task_A2G, @N=onafterEngage, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=6214, +@K=function, @M=Task_A2G, @N=onafterRouteToTarget, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=6536, +@K=function, @M=Task_A2G, @N=onafterRouteToTargets, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=7408, +@K=function, @M=Task_Cargo, @N=onafterSelectAction, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=10439, +@K=function, @M=Task_Cargo, @N=OnLeaveWaitingForCommand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13082, +@K=function, @M=Task_Cargo, @N=onafterRouteToPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13858, +@K=function, @M=Task_Cargo, @N=onafterArriveAtPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=14477, +@K=function, @M=Task_Cargo, @N=onafterRouteToDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15018, +@K=function, @M=Task_Cargo, @N=onafterArriveAtDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15465, +@K=function, @M=Task_Cargo, @N=onafterLand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15895, +@K=function, @M=Task_Cargo, @N=onafterLanded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=16854, +@K=function, @M=Task_Cargo, @N=onafterPrepareBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=17620, +@K=function, @M=Task_Cargo, @N=onafterBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=18080, +@K=function, @M=Task_Cargo, @N=onafterBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19021, +@K=function, @M=Task_Cargo, @N=onafterPrepareUnBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19704, +@K=function, @M=Task_Cargo, @N=onafterUnBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=20664, +@K=function, @M=Task_Cargo, @N=onafterUnBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=21539, @K=function, @M=Designate, @N=OnBeforeLaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12232, @K=function, @M=Designate, @N=OnAfterLaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12480, @K=function, @M=Designate, @N=LaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12701, diff --git a/docs/Documentation/AI_BAI.html b/docs/Documentation/AI_BAI.html new file mode 100644 index 000000000..2234f5318 --- /dev/null +++ b/docs/Documentation/AI_BAI.html @@ -0,0 +1,1875 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_BAI

+ +

AI -- Provide Battleground Air Interdiction (bombing).

+ +

Banner Image

+ +
+ +

AI_BAI classes makes AI Controllables execute bombing tasks.

+ + + +

There are the following types of BAI classes defined:

+ + + +
+ +

Demo Missions

+ +

AI_BAI Demo Missions source code

+ +

AI_BAI Demo Missions, only for beta testers

+ +

ALL Demo Missions pack of the last release

+ +
+ +

YouTube Channel

+ +

AI_BAI YouTube Channel

+ +
+ +

API CHANGE HISTORY

+ +

The underlying change log documents the API changes. Please read this carefully. The following notation is used:

+ +
    +
  • Added parts are expressed in bold type face.
  • +
  • Removed parts are expressed in italic type face.
  • +
+ +

Hereby the change log:

+ +

2017-01-15: Initial class and API.

+ +
+ +

AUTHORS and CONTRIBUTIONS

+ +

Contributions:

+ + + +

Authors:

+ +
    +
  • FlightControl: Concept, Design & Programming.
  • +
+ + +

Global(s)

+ + + + + + + + + +
AI_BAI_ZONE +

AIBAIZONE class, extends AIPatrol#AIPATROL_ZONE

+ +

AIBAIZONE derives from the AIPatrol#AIPATROL_ZONE, inheriting its methods and behaviour.

+
_NewEngageRoute(AIControllable) + +
+

Type AI_BAI_ZONE

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_BAI_ZONE.AIControllable +

The Controllable patrolling.

+
AI_BAI_ZONE:Abort() +

Synchronous Event Trigger for Event Abort.

+
AI_BAI_ZONE:Accomplish() +

Synchronous Event Trigger for Event Accomplish.

+
AI_BAI_ZONE.Accomplished + +
AI_BAI_ZONE:Destroy() +

Synchronous Event Trigger for Event Destroy.

+
AI_BAI_ZONE:Engage(EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) +

Synchronous Event Trigger for Event Engage.

+
AI_BAI_ZONE.EngageAltitude + +
AI_BAI_ZONE.EngageAttackQty + +
AI_BAI_ZONE.EngageDirection + +
AI_BAI_ZONE.EngageSpeed + +
AI_BAI_ZONE.EngageWeaponExpend + +
AI_BAI_ZONE.EngageZone + +
AI_BAI_ZONE:Fired() +

Synchronous Event Trigger for Event Fired.

+
AI_BAI_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType) +

Creates a new AIBAIZONE object

+
AI_BAI_ZONE:OnAfterAbort(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Abort.

+
AI_BAI_ZONE:OnAfterAccomplish(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Accomplish.

+
AI_BAI_ZONE:OnAfterDestroy(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Destroy.

+
AI_BAI_ZONE:OnAfterEngage(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Engage.

+
AI_BAI_ZONE:OnAfterFired(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Fired.

+
AI_BAI_ZONE:OnBeforeAbort(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Abort.

+
AI_BAI_ZONE:OnBeforeAccomplish(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Accomplish.

+
AI_BAI_ZONE:OnBeforeDestroy(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Destroy.

+
AI_BAI_ZONE:OnBeforeEngage(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Engage.

+
AI_BAI_ZONE:OnBeforeFired(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Fired.

+
AI_BAI_ZONE:OnEnterEngaging(Controllable, From, Event, To) +

OnEnter Transition Handler for State Engaging.

+
AI_BAI_ZONE:OnEventDead(EventData) + +
AI_BAI_ZONE:OnLeaveEngaging(Controllable, From, Event, To) +

OnLeave Transition Handler for State Engaging.

+
AI_BAI_ZONE:SetEngageZone(EngageZone) +

Set the Engage Zone where the AI is performing BOMB.

+
AI_BAI_ZONE.TargetZone +

The Zone where the patrol needs to be executed.

+
AI_BAI_ZONE:__Abort(Delay) +

Asynchronous Event Trigger for Event Abort.

+
AI_BAI_ZONE:__Accomplish(Delay) +

Asynchronous Event Trigger for Event Accomplish.

+
AI_BAI_ZONE:__Destroy(Delay) +

Asynchronous Event Trigger for Event Destroy.

+
AI_BAI_ZONE:__Engage(Delay, EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) +

Asynchronous Event Trigger for Event Engage.

+
AI_BAI_ZONE:__Fired(Delay) +

Asynchronous Event Trigger for Event Fired.

+
AI_BAI_ZONE:onafterAbort(Controllable, From, Event, To) + +
AI_BAI_ZONE:onafterAccomplish(Controllable, From, Event, To) + +
AI_BAI_ZONE:onafterDestroy(Controllable, From, Event, To, EventData) + +
AI_BAI_ZONE:onafterEngage(Controllable, From, Event, To, EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) + +
AI_BAI_ZONE:onafterStart(Controllable, From, Event, To) +

onafter State Transition for Event Start.

+
AI_BAI_ZONE:onafterTarget(Controllable, From, Event, To) + +
AI_BAI_ZONE:onbeforeEngage(Controllable, From, Event, To) + +
+ +

Global(s)

+
+
+ + #AI_BAI_ZONE + +AI_BAI_ZONE + +
+
+ +

AIBAIZONE class, extends AIPatrol#AIPATROL_ZONE

+ +

AIBAIZONE derives from the AIPatrol#AIPATROL_ZONE, inheriting its methods and behaviour.

+ + +

+The AIBAIZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage Zone by an AIR Controllable or Group. +The AIBAIZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.

+ +

HoldAndEngage

+ +

The AIBAIZONE is assigned a Group and this must be done before the AIBAIZONE process can be started through the Start event.

+ +

Start Event

+ +

Upon started, The AI will Route itself towards the random 3D point within a patrol zone, +using a random speed within the given altitude and speed limits. +Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits. +This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.

+ +

Route Event

+ +

When the AI is commanded to provide BattleGround Air Interdiction (through the event Engage), the AI will fly towards the Engage Zone. +Any target that is detected in the Engage Zone will be reported and will be destroyed by the AI.

+ +

Engage Event

+ +

The AI will detect the targets and will only destroy the targets within the Engage Zone.

+ +

Engage Event

+ +

Every target that is destroyed, is reported< by the AI.

+ +

Engage Event

+ +

Note that the AI does not know when the Engage Zone is cleared, and therefore will keep circling in the zone.

+ +

Engage Event

+ +

Until it is notified through the event Accomplish, which is to be triggered by an observing party:

+ +
    +
  • a FAC
  • +
  • a timed event
  • +
  • a menu option selected by a human
  • +
  • a condition
  • +
  • others ...
  • +
+ +

Engage Event

+ +

When the AI has accomplished the BOMB, it will fly back to the Patrol Zone.

+ +

Engage Event

+ +

It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone. +It can be notified to go RTB through the RTB event.

+ +

When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.

+ +

Engage Event

+ +

1. AIBAIZONE constructor

+ + + +

2. AIBAIZONE is a FSM

+ +

Process

+ +

2.1. AIBAIZONE States

+ +
    +
  • None ( Group ): The process is not started yet.
  • +
  • Patrolling ( Group ): The AI is patrolling the Patrol Zone.
  • +
  • Engaging ( Group ): The AI is engaging the targets in the Engage Zone, executing BOMB.
  • +
  • Returning ( Group ): The AI is returning to Base..
  • +
+ +

2.2. AIBAIZONE Events

+ + + +
+ + +
+
+
+
+ + +_NewEngageRoute(AIControllable) + +
+
+ + + +

Parameter

+ +
+
+

Type AI_BAI

+ +

Type AI_BAI_ZONE

+ +

AIBAIZONE class

+ +

Field(s)

+
+
+ + Wrapper.Controllable#CONTROLLABLE + +AI_BAI_ZONE.AIControllable + +
+
+ +

The Controllable patrolling.

+ +
+
+
+
+ + +AI_BAI_ZONE:Abort() + +
+
+ +

Synchronous Event Trigger for Event Abort.

+ +
+
+
+
+ + +AI_BAI_ZONE:Accomplish() + +
+
+ +

Synchronous Event Trigger for Event Accomplish.

+ +
+
+
+
+ + #boolean + +AI_BAI_ZONE.Accomplished + +
+
+ + + +
+
+
+
+ + +AI_BAI_ZONE:Destroy() + +
+
+ +

Synchronous Event Trigger for Event Destroy.

+ +
+
+
+
+ + +AI_BAI_ZONE:Engage(EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) + +
+
+ +

Synchronous Event Trigger for Event Engage.

+ +

Parameters

+
    +
  • + +

    #number EngageSpeed : +(optional) The speed the Group will hold when engaging to the target zone.

    + +
  • +
  • + +

    Dcs.DCSTypes#Distance EngageAltitude : +(optional) Desired altitude to perform the unit engagement.

    + +
  • +
  • + +

    Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend : +(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. +Use the structure DCSTypes#AI.Task.WeaponExpend to define the amount of weapons to be release at each attack.

    + +
  • +
  • + +

    #number EngageAttackQty : +(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.

    + +
  • +
  • + +

    Dcs.DCSTypes#Azimuth EngageDirection : +(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.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE.EngageAltitude + +
+
+ + + +
+
+
+
+ + + +AI_BAI_ZONE.EngageAttackQty + +
+
+ + + +
+
+
+
+ + + +AI_BAI_ZONE.EngageDirection + +
+
+ + + +
+
+
+
+ + +AI_BAI_ZONE.EngageSpeed + +
+
+ + + +
+
+
+
+ + + +AI_BAI_ZONE.EngageWeaponExpend + +
+
+ + + +
+
+
+
+ + + +AI_BAI_ZONE.EngageZone + +
+
+ + + +
+
+
+
+ + +AI_BAI_ZONE:Fired() + +
+
+ +

Synchronous Event Trigger for Event Fired.

+ +
+
+
+
+ + +AI_BAI_ZONE:New(PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType) + +
+
+ +

Creates a new AIBAIZONE object

+ +

Parameters

+ +

Return value

+ +

#AIBAIZONE: +self

+ +
+
+
+
+ + +AI_BAI_ZONE:OnAfterAbort(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnAfterAccomplish(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnAfterDestroy(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnAfterEngage(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnAfterFired(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnBeforeAbort(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_BAI_ZONE:OnBeforeAccomplish(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_BAI_ZONE:OnBeforeDestroy(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_BAI_ZONE:OnBeforeEngage(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnBeforeFired(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_BAI_ZONE:OnEnterEngaging(Controllable, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:OnEventDead(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_BAI_ZONE:OnLeaveEngaging(Controllable, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_BAI_ZONE:SetEngageZone(EngageZone) + +
+
+ +

Set the Engage Zone where the AI is performing BOMB.

+ + +

Note that if the EngageZone is changed, the AI needs to re-detect targets.

+ +

Parameter

+
    +
  • + +

    Core.Zone#ZONE EngageZone : +The zone where the AI is performing BOMB.

    + +
  • +
+

Return value

+ +

#AIBAIZONE: +self

+ +
+
+
+
+ + Core.Zone#ZONE_BASE + +AI_BAI_ZONE.TargetZone + +
+
+ +

The Zone where the patrol needs to be executed.

+ +
+
+
+
+ + +AI_BAI_ZONE:__Abort(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Abort.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:__Accomplish(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Accomplish.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:__Destroy(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Destroy.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:__Engage(Delay, EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) + +
+
+ +

Asynchronous Event Trigger for Event Engage.

+ +

Parameters

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
  • + +

    #number EngageSpeed : +(optional) The speed the Group will hold when engaging to the target zone.

    + +
  • +
  • + +

    Dcs.DCSTypes#Distance EngageAltitude : +(optional) Desired altitude to perform the unit engagement.

    + +
  • +
  • + +

    Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend : +(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. +Use the structure DCSTypes#AI.Task.WeaponExpend to define the amount of weapons to be release at each attack.

    + +
  • +
  • + +

    #number EngageAttackQty : +(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.

    + +
  • +
  • + +

    Dcs.DCSTypes#Azimuth EngageDirection : +(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.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:__Fired(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Fired.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterAbort(Controllable, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterAccomplish(Controllable, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterDestroy(Controllable, From, Event, To, EventData) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    Core.Event#EVENTDATA EventData :

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterEngage(Controllable, From, Event, To, EngageSpeed, EngageAltitude, EngageWeaponExpend, EngageAttackQty, EngageDirection) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    #number EngageSpeed : +(optional) The speed the Group will hold when engaging to the target zone.

    + +
  • +
  • + +

    Dcs.DCSTypes#Distance EngageAltitude : +(optional) Desired altitude to perform the unit engagement.

    + +
  • +
  • + +

    Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend : +(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.

    + +
  • +
  • + +

    #number EngageAttackQty : +(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.

    + +
  • +
  • + +

    Dcs.DCSTypes#Azimuth EngageDirection : +(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.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterStart(Controllable, From, Event, To) + +
+
+ +

onafter State Transition for Event Start.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onafterTarget(Controllable, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_BAI_ZONE:onbeforeEngage(Controllable, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+ +
+ +
+ + diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 230ca6776..8230fd694 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/AI_Cap.html b/docs/Documentation/AI_Cap.html index 963e9394c..a87487c58 100644 --- a/docs/Documentation/AI_Cap.html +++ b/docs/Documentation/AI_Cap.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/AI_Cas.html b/docs/Documentation/AI_Cas.html index e95a2aae3..f99458bb4 100644 --- a/docs/Documentation/AI_Cas.html +++ b/docs/Documentation/AI_Cas.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index 21275d1d5..ab0dc233e 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Account.html b/docs/Documentation/Account.html index 089c174b7..40cca1764 100644 --- a/docs/Documentation/Account.html +++ b/docs/Documentation/Account.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Airbase.html b/docs/Documentation/Airbase.html index 3696e79c3..439ea2f1b 100644 --- a/docs/Documentation/Airbase.html +++ b/docs/Documentation/Airbase.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/AirbasePolice.html b/docs/Documentation/AirbasePolice.html index 54530566c..8a03b3a59 100644 --- a/docs/Documentation/AirbasePolice.html +++ b/docs/Documentation/AirbasePolice.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Assign.html b/docs/Documentation/Assign.html index df974383f..1565398e5 100644 --- a/docs/Documentation/Assign.html +++ b/docs/Documentation/Assign.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Base.html b/docs/Documentation/Base.html index d3da0af2f..64657992b 100644 --- a/docs/Documentation/Base.html +++ b/docs/Documentation/Base.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index a9b110ac2..0b2f68352 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Client.html b/docs/Documentation/Client.html index f28f29238..472bbe443 100644 --- a/docs/Documentation/Client.html +++ b/docs/Documentation/Client.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/CommandCenter.html b/docs/Documentation/CommandCenter.html index 7b2d84919..bcf88684a 100644 --- a/docs/Documentation/CommandCenter.html +++ b/docs/Documentation/CommandCenter.html @@ -17,6 +17,7 @@ index
diff --git a/docs/Documentation/DCSAirbase.html b/docs/Documentation/DCSAirbase.html index 01bc9464a..f9b40732f 100644 --- a/docs/Documentation/DCSAirbase.html +++ b/docs/Documentation/DCSAirbase.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSCoalitionObject.html b/docs/Documentation/DCSCoalitionObject.html index bb7ebcfcb..5d9721659 100644 --- a/docs/Documentation/DCSCoalitionObject.html +++ b/docs/Documentation/DCSCoalitionObject.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSCommand.html b/docs/Documentation/DCSCommand.html index 91c30c853..918aba934 100644 --- a/docs/Documentation/DCSCommand.html +++ b/docs/Documentation/DCSCommand.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSController.html b/docs/Documentation/DCSController.html index 1e5034deb..c8f091a16 100644 --- a/docs/Documentation/DCSController.html +++ b/docs/Documentation/DCSController.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSGroup.html b/docs/Documentation/DCSGroup.html index fa9675c4a..f5cf0300e 100644 --- a/docs/Documentation/DCSGroup.html +++ b/docs/Documentation/DCSGroup.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSObject.html b/docs/Documentation/DCSObject.html index ef4007524..aa771f73d 100644 --- a/docs/Documentation/DCSObject.html +++ b/docs/Documentation/DCSObject.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSTask.html b/docs/Documentation/DCSTask.html index 49ee84e3f..bdab8ced8 100644 --- a/docs/Documentation/DCSTask.html +++ b/docs/Documentation/DCSTask.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSTypes.html b/docs/Documentation/DCSTypes.html index 89bfc6f76..68b115ab2 100644 --- a/docs/Documentation/DCSTypes.html +++ b/docs/Documentation/DCSTypes.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSUnit.html b/docs/Documentation/DCSUnit.html index dd2ee830e..ff49c3ce0 100644 --- a/docs/Documentation/DCSUnit.html +++ b/docs/Documentation/DCSUnit.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSVec3.html b/docs/Documentation/DCSVec3.html index b774c20dd..bae815190 100644 --- a/docs/Documentation/DCSVec3.html +++ b/docs/Documentation/DCSVec3.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSWorld.html b/docs/Documentation/DCSWorld.html index 14dffe7a6..8cf46e3e9 100644 --- a/docs/Documentation/DCSWorld.html +++ b/docs/Documentation/DCSWorld.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCSZone.html b/docs/Documentation/DCSZone.html index 1ca1e8eaf..dcfed9d0f 100644 --- a/docs/Documentation/DCSZone.html +++ b/docs/Documentation/DCSZone.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCScountry.html b/docs/Documentation/DCScountry.html index 2918281ca..3513b9812 100644 --- a/docs/Documentation/DCScountry.html +++ b/docs/Documentation/DCScountry.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCStimer.html b/docs/Documentation/DCStimer.html index 70c8b9c64..1822b7fbc 100644 --- a/docs/Documentation/DCStimer.html +++ b/docs/Documentation/DCStimer.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/DCStrigger.html b/docs/Documentation/DCStrigger.html index ec6e651a8..0a12a11e5 100644 --- a/docs/Documentation/DCStrigger.html +++ b/docs/Documentation/DCStrigger.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index bdaa3f280..13c610e53 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -890,7 +891,6 @@ function below will use the range 1-7 just in case

    - DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 4514b29c5..e512594d8 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -2322,7 +2323,6 @@ The index of the DetectedItem.

    - #number DETECTION_BASE.DetectedItemCount diff --git a/docs/Documentation/DetectionManager.html b/docs/Documentation/DetectionManager.html index 69181e750..b5aea1316 100644 --- a/docs/Documentation/DetectionManager.html +++ b/docs/Documentation/DetectionManager.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Escort.html b/docs/Documentation/Escort.html index d1e785017..a43ecab35 100644 --- a/docs/Documentation/Escort.html +++ b/docs/Documentation/Escort.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Event.html b/docs/Documentation/Event.html index b43313153..bfa3823de 100644 --- a/docs/Documentation/Event.html +++ b/docs/Documentation/Event.html @@ -17,6 +17,7 @@ index
+ +
+
+ + +EVENT:CreateEventPlayerEnterUnit(PlayerUnit) + +
+
+ +

Creation of a SEVENTPLAYERENTERUNIT Event.

+ +

Parameter

+ +
diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index 425da196e..b832094de 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -1622,7 +1623,7 @@ A string defining the start state.

    - #string + FSM._StartState @@ -1921,6 +1922,7 @@ A string defining the start state.

    + FSM.current diff --git a/docs/Documentation/Group.html b/docs/Documentation/Group.html index 9f0a9032c..d970725e0 100644 --- a/docs/Documentation/Group.html +++ b/docs/Documentation/Group.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Identifiable.html b/docs/Documentation/Identifiable.html index 09726bbec..c049a8f65 100644 --- a/docs/Documentation/Identifiable.html +++ b/docs/Documentation/Identifiable.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Menu.html b/docs/Documentation/Menu.html index a108b8568..f294044d9 100644 --- a/docs/Documentation/Menu.html +++ b/docs/Documentation/Menu.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Message.html b/docs/Documentation/Message.html index 0b06cafbb..3d8c4d78f 100644 --- a/docs/Documentation/Message.html +++ b/docs/Documentation/Message.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/MissileTrainer.html b/docs/Documentation/MissileTrainer.html index 163c4d7fb..88159742b 100644 --- a/docs/Documentation/MissileTrainer.html +++ b/docs/Documentation/MissileTrainer.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Mission.html b/docs/Documentation/Mission.html index 96f09fc56..fa18d7ec0 100644 --- a/docs/Documentation/Mission.html +++ b/docs/Documentation/Mission.html @@ -17,6 +17,7 @@ index

Return value

-

#boolean: -true if Unit is part of a Task in the Mission.

+

#MISSION:

+
@@ -601,6 +644,20 @@ is the Task object.

Tasking.Task#TASK: The task added.

+ + +
+
+ + + +MISSION.AssignedGroups + +
+
+ + +
@@ -615,6 +672,32 @@ The task added.

+ +
+
+
+ + +MISSION:ClearGroupAssignment(MissionGroup) + +
+
+ +

Clear the Group assignment from the Mission.

+ +

Parameter

+ +

Return value

+ +

#MISSION:

+ +
@@ -657,8 +740,8 @@ The CLIENT or UNIT of the Player crashing.

Return value

-

#boolean: -true if Unit is part of a Task in the Mission.

+

#MISSION:

+
@@ -840,6 +923,24 @@ Returns nil if no task was found.

+ +MISSION:GetTaskTypes() + +
+
+ + + +

Return value

+ +

#number:

+ + +
+
+
+
+ MISSION:GetTasks() @@ -970,6 +1071,32 @@ true if the Mission has a Group.

#boolean:

+ +
+
+
+ + +MISSION:IsGroupAssigned(MissionGroup) + +
+
+ +

Returns if the Mission is assigned to the Group.

+ +

Parameter

+ +

Return value

+ +

#boolean:

+ +
@@ -1907,6 +2034,67 @@ self

#string:

+ +
+
+
+ + +MISSION:ReportPlayers() + +
+
+ +

Create a player report of the Mission.

+ + +

This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.

+ +
Mission "<MissionName>" - Status "<MissionStatus>"
+ - Player "<PlayerName>: Task <TaskName> <TaskStatus>, Task <TaskName> <TaskStatus>
+ - Player <PlayerName>: Task <TaskName> <TaskStatus>, Task <TaskName> <TaskStatus>
+ - ..
+
+ + +

Return value

+ +

#string:

+ + +
+
+
+
+ + +MISSION:ReportStatus() + +
+
+ +

Create a status report of the Mission.

+ + +

This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.

+ +
Mission "<MissionName>" - Status "<MissionStatus>"
+ - Task Types: <TaskType>, <TaskType>
+ - <xx> Planned Tasks (xp)
+ - <xx> Assigned Tasks(xp)
+ - <xx> Success Tasks (xp)
+ - <xx> Hold Tasks (xp)
+ - <xx> Cancelled Tasks (xp)
+ - <xx> Aborted Tasks (xp)
+ - <xx> Failed Tasks (xp)
+
+ + +

Return value

+ +

#string:

+ +
@@ -1939,6 +2127,32 @@ self

+ +
+
+
+ + +MISSION:SetGroupAssigned(MissionGroup) + +
+
+ +

Set Group assigned to the Mission.

+ +

Parameter

+ +

Return value

+ +

#MISSION:

+ +
diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index a7de96e12..3adb3bd89 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index eb4b6b090..63145ee4b 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Point.html b/docs/Documentation/Point.html index c2551b2fa..d487eeafe 100644 --- a/docs/Documentation/Point.html +++ b/docs/Documentation/Point.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -1971,6 +1972,7 @@ The new calculated POINT_VEC2.

    + POINT_VEC2.z diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index 750f76f48..d9dea20e8 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -17,6 +17,7 @@ index
diff --git a/docs/Documentation/Process_JTAC.html b/docs/Documentation/Process_JTAC.html index 2f5617745..9e073a5a6 100644 --- a/docs/Documentation/Process_JTAC.html +++ b/docs/Documentation/Process_JTAC.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Process_Pickup.html b/docs/Documentation/Process_Pickup.html index f3c04bde3..20b6065b6 100644 --- a/docs/Documentation/Process_Pickup.html +++ b/docs/Documentation/Process_Pickup.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Radio.html b/docs/Documentation/Radio.html index 49e33bb80..74bfa4e8c 100644 --- a/docs/Documentation/Radio.html +++ b/docs/Documentation/Radio.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Route.html b/docs/Documentation/Route.html index 4baad755b..4b4f79333 100644 --- a/docs/Documentation/Route.html +++ b/docs/Documentation/Route.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Scenery.html b/docs/Documentation/Scenery.html index e67b955d0..114319f43 100644 --- a/docs/Documentation/Scenery.html +++ b/docs/Documentation/Scenery.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/ScheduleDispatcher.html b/docs/Documentation/ScheduleDispatcher.html index e64ef01f1..c5292e224 100644 --- a/docs/Documentation/ScheduleDispatcher.html +++ b/docs/Documentation/ScheduleDispatcher.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Scheduler.html b/docs/Documentation/Scheduler.html index e995868a6..7981b1438 100644 --- a/docs/Documentation/Scheduler.html +++ b/docs/Documentation/Scheduler.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Scoring.html b/docs/Documentation/Scoring.html index 9df3c05db..322b24998 100644 --- a/docs/Documentation/Scoring.html +++ b/docs/Documentation/Scoring.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Sead.html b/docs/Documentation/Sead.html index 9dcd22068..dbf3167ec 100644 --- a/docs/Documentation/Sead.html +++ b/docs/Documentation/Sead.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Set.html b/docs/Documentation/Set.html index fee8d1931..56e79058a 100644 --- a/docs/Documentation/Set.html +++ b/docs/Documentation/Set.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -976,6 +977,12 @@ mission designer to add a dedicated method

    Iterate the SET_UNIT sorted *per Threat Level and call an interator function for each alive UNIT, providing the UNIT and optional parameters.

    + + + + SET_UNIT:GetFirst() + +

    Get the first unit from the set.

    @@ -4817,6 +4824,24 @@ self

    + +SET_UNIT:GetFirst() + +
    +
    + +

    Get the first unit from the set.

    + +

    Return value

    + +

    Wrapper.Unit#UNIT: +The UNIT object.

    + +
    +
    +
    +
    + SET_UNIT:GetTypeNames(Delimiter) diff --git a/docs/Documentation/Smoke.html b/docs/Documentation/Smoke.html index c59546f49..136d8ac61 100644 --- a/docs/Documentation/Smoke.html +++ b/docs/Documentation/Smoke.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 05374facf..6bbc5b660 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -17,6 +17,7 @@ index
@@ -2541,6 +2545,9 @@ when nothing was spawned.

+ +

By default, no InitLimit

+
@@ -2576,7 +2583,7 @@ when nothing was spawned.

- + #number SPAWN.SpawnMaxGroups @@ -2593,7 +2600,7 @@ when nothing was spawned.

- + #number SPAWN.SpawnMaxUnitsAlive diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index aac7b1703..d1a622752 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -444,7 +445,6 @@ ptional) The name of the new static.

    - #number SPAWNSTATIC.SpawnIndex diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index 8e9ea64bc..acc195246 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • @@ -761,6 +762,7 @@ true if it is lasing

    + SPOT.ScheduleID @@ -774,6 +776,7 @@ true if it is lasing

    + SPOT.SpotIR @@ -787,6 +790,7 @@ true if it is lasing

    + SPOT.SpotLaser @@ -800,6 +804,7 @@ true if it is lasing

    + SPOT.Target diff --git a/docs/Documentation/Static.html b/docs/Documentation/Static.html index 48567e339..ffa9fdb0e 100644 --- a/docs/Documentation/Static.html +++ b/docs/Documentation/Static.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/StaticObject.html b/docs/Documentation/StaticObject.html index 40915b9d3..b8eff3eed 100644 --- a/docs/Documentation/StaticObject.html +++ b/docs/Documentation/StaticObject.html @@ -17,6 +17,7 @@ index
    +
  • AI_BAI
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • diff --git a/docs/Documentation/Task.html b/docs/Documentation/Task.html index 87c1f6f63..32e192c3f 100644 --- a/docs/Documentation/Task.html +++ b/docs/Documentation/Task.html @@ -17,6 +17,7 @@ index
+
+
+ + +TASK:ClearGroupAssignment(TaskGroup) + +
+
+ +

Clear the Group assignment from the Task.

+ +

Parameter

+ +

Return value

+ +

#TASK:

+ +
@@ -918,8 +986,8 @@ self

- -TASK:CrashUnit(PlayerUnit) + +TASK:CrashGroup(PlayerUnit, PlayerGroup)
@@ -931,19 +999,24 @@ self

If the Unit was not part of the Task, false is returned. If the Unit is part of the Task, true is returned.

-

Parameter

+

Parameters

  • Wrapper.Unit#UNIT PlayerUnit : The CLIENT or UNIT of the Player aborting the Task.

    +
  • +
  • + +

    PlayerGroup :

    +

Return value

-

#boolean: -true if Unit is part of the Task.

+

#TASK:

+
@@ -1017,6 +1090,24 @@ true if Unit is part of the Task.

+ +
+
+
+ + +TASK:GetBriefing() + +
+
+ +

Gets the Task briefing.

+ +

Return value

+ +

#string: +The briefing text.

+
@@ -1094,6 +1185,42 @@ The Task Name

+ +TASK:GetPlayerCount() + +
+
+ +

Create a count of the players in the Task.

+ +

Return value

+ +

#number: +The total number of players in the task.

+ +
+
+
+
+ + +TASK:GetPlayerNames() + +
+
+ +

Create a list of the players in the Task.

+ +

Return value

+ +

#map:

+

string,Wrapper.Group#GROUP> A map of the players

+ +
+
+
+
+ TASK:GetProcessTemplate(ProcessName) @@ -1177,6 +1304,24 @@ Scoring

+ +TASK:GetTaskBriefing() + +
+
+ +

Returns the Task briefing.

+ +

Return value

+ +

#string: +Task briefing.

+ +
+
+
+
+ TASK:GetTaskIndex() @@ -1327,8 +1472,8 @@ self

- -TASK:IsAssignedToGroup(TaskGroup) + +TASK:IsGroupAssigned(TaskGroup)
@@ -1594,7 +1739,7 @@ true if Unit is part of the Task.

-TASK:New(Mission, SetGroupAssign, TaskName, TaskType) +TASK:New(Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing)
@@ -1629,6 +1774,11 @@ The name of the Task

#string TaskType : The type of the Task

+ +
  • + +

    TaskBriefing :

    +
  • Return value

    @@ -1725,6 +1875,37 @@ The name of the Player.

    + +TASK:RefreshMenus(TaskGroup, MenuTime) + +
    +
    + +

    Remove the menu option of the Task for a Group.

    + +

    Parameters

    + +

    Return value

    + +

    #TASK: +self

    + +
    +
    +
    +
    + TASK:RemoveAssignedMenuForGroup(TaskGroup, MenuTime) @@ -1777,37 +1958,6 @@ self

    #TASK:

    -
    -
    -
    -
    - - -TASK:RemovePlannedMenuForGroup(TaskGroup, MenuTime) - -
    -
    - -

    Remove the menu option of the Task for a Group.

    - -

    Parameters

    - -

    Return value

    - -

    #TASK: -self

    -
    @@ -2023,6 +2173,32 @@ self

    The Set of Groups assigned to the Task

    + +
    +
    +
    + + +TASK:SetGroupAssigned(TaskGroup) + +
    +
    + +

    Set Group assigned to the Task.

    + +

    Parameter

    + +

    Return value

    + +

    #TASK:

    + +
    @@ -2901,6 +3077,8 @@ self

    Type integer

    +

    Type map

    +
    diff --git a/docs/Documentation/Task_A2G.html b/docs/Documentation/Task_A2G.html index 48a7ba5f0..fd355500d 100644 --- a/docs/Documentation/Task_A2G.html +++ b/docs/Documentation/Task_A2G.html @@ -17,6 +17,7 @@ index

    Return value

    @@ -900,7 +906,7 @@ The Zone object where the Target is located on the map.

    -TASK_BAI:New(Mission, SetGroup, TaskName, UnitSetTargets, TargetDistance, TargetZone, TargetSetUnit) +TASK_BAI:New(Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing)
    @@ -916,7 +922,7 @@ The Zone object where the Target is located on the map.

  • -

    Set#SET_GROUP SetGroup : +

    Core.Set#SET_GROUP SetGroup : The set of groups for which the Task can be assigned.

  • @@ -928,25 +934,13 @@ The name of the Task.

  • -

    Set#SET_UNIT UnitSetTargets :

    +

    Core.Set#SET_UNIT TargetSetUnit :

  • -

    #number TargetDistance : -The distance to Target when the Player is considered to have "arrived" at the engagement range.

    - -
  • -
  • - -

    Core.Zone#ZONE_BASE TargetZone : -The target zone, if known. -If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be.

    - -
  • -
  • - -

    TargetSetUnit :

    +

    #string TaskBriefing : +The briefing of the task.

  • @@ -995,7 +989,7 @@ self

    -TASK_CAS:New(Mission, SetGroup, TaskName, UnitSetTargets, TargetDistance, TargetZone, TargetSetUnit) +TASK_CAS:New(Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing)
    @@ -1011,7 +1005,7 @@ self

  • -

    Set#SET_GROUP SetGroup : +

    Core.Set#SET_GROUP SetGroup : The set of groups for which the Task can be assigned.

  • @@ -1023,25 +1017,13 @@ The name of the Task.

  • -

    Set#SET_UNIT UnitSetTargets :

    +

    Core.Set#SET_UNIT TargetSetUnit :

  • -

    #number TargetDistance : -The distance to Target when the Player is considered to have "arrived" at the engagement range.

    - -
  • -
  • - -

    Core.Zone#ZONE_BASE TargetZone : -The target zone, if known. -If the TargetZone parameter is specified, the player will be routed to the center of the zone where all the targets are assumed to be.

    - -
  • -
  • - -

    TargetSetUnit :

    +

    #string TaskBriefing : +The briefing of the task.

  • @@ -1090,7 +1072,7 @@ self

    -TASK_SEAD:New(Mission, SetGroup, TaskName, TargetSetUnit) +TASK_SEAD:New(Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing)
    @@ -1106,7 +1088,7 @@ self

  • -

    Set#SET_GROUP SetGroup : +

    Core.Set#SET_GROUP SetGroup : The set of groups for which the Task can be assigned.

  • @@ -1118,7 +1100,13 @@ The name of the Task.

  • -

    Set#SET_UNIT TargetSetUnit :

    +

    Core.Set#SET_UNIT TargetSetUnit :

    + +
  • +
  • + +

    #string TaskBriefing : +The briefing of the task.

  • diff --git a/docs/Documentation/Task_A2G_Dispatcher.html b/docs/Documentation/Task_A2G_Dispatcher.html index 197ead2ef..54ba3cfa4 100644 --- a/docs/Documentation/Task_A2G_Dispatcher.html +++ b/docs/Documentation/Task_A2G_Dispatcher.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index a05a4ee40..5cb0f06fd 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -17,6 +17,7 @@ index

    Return value

    @@ -936,6 +991,68 @@ The score in points.

    + +TASK_CARGO_TRANSPORT:CargoDeployed(TaskUnit, Cargo, DeployZone) + +
    +
    + +

    Synchronous Event Trigger for Event CargoDeployed.

    + +

    Parameters

    +
      +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    • + +

      Core.Zone#ZONE DeployZone : +The zone where the Cargo got Deployed or UnBoarded.

      + +
    • +
    +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:CargoPickedUp(TaskUnit, Cargo) + +
    +
    + +

    Synchronous Event Trigger for Event CargoPickedUp.

    + +

    Parameters

    +
      +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    +
    +
    +
    +
    + #string TASK_CARGO_TRANSPORT.ClassName @@ -969,7 +1086,7 @@ The score in points.

    -TASK_CARGO_TRANSPORT:New(Mission, SetGroup, TaskName, SetCargo) +TASK_CARGO_TRANSPORT:New(Mission, SetGroup, TaskName, SetCargo, TaskBriefing)
    @@ -1000,6 +1117,12 @@ The name of the Task.

    Core.Set#SET_CARGO SetCargo : The scope of the cargo to be transported.

    + +
  • + +

    #string TaskBriefing : +The Cargo Task briefing.

    +
  • Return value

    @@ -1007,6 +1130,286 @@ The scope of the cargo to be transported.

    #TASKCARGOTRANSPORT: self

    +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:OnAfterCargoDeployed(From, Event, To, TaskUnit, Cargo, DeployZone) + +
    +
    + +

    OnAfter Transition Handler for Event CargoDeployed.

    + +

    Parameters

    +
      +
    • + +

      #string From : +The From State string.

      + +
    • +
    • + +

      #string Event : +The Event string.

      + +
    • +
    • + +

      #string To : +The To State string.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    • + +

      Core.Zone#ZONE DeployZone : +The zone where the Cargo got Deployed or UnBoarded.

      + +
    • +
    +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:OnAfterCargoPickedUp(From, Event, To, TaskUnit, Cargo) + +
    +
    + +

    OnAfter Transition Handler for Event CargoPickedUp.

    + +

    Parameters

    +
      +
    • + +

      #string From : +The From State string.

      + +
    • +
    • + +

      #string Event : +The Event string.

      + +
    • +
    • + +

      #string To : +The To State string.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:OnBeforeCargoDeployed(From, Event, To, TaskUnit, Cargo, DeployZone) + +
    +
    + +

    OnBefore Transition Handler for Event CargoDeployed.

    + +

    Parameters

    +
      +
    • + +

      #string From : +The From State string.

      + +
    • +
    • + +

      #string Event : +The Event string.

      + +
    • +
    • + +

      #string To : +The To State string.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    • + +

      Core.Zone#ZONE DeployZone : +The zone where the Cargo got Deployed or UnBoarded.

      + +
    • +
    +

    Return value

    + +

    #boolean: +Return false to cancel Transition.

    + +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:OnBeforeCargoPickedUp(From, Event, To, TaskUnit, Cargo) + +
    +
    + +

    OnBefore Transition Handler for Event CargoPickedUp.

    + +

    Parameters

    +
      +
    • + +

      #string From : +The From State string.

      + +
    • +
    • + +

      #string Event : +The Event string.

      + +
    • +
    • + +

      #string To : +The To State string.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    +

    Return value

    + +

    #boolean: +Return false to cancel Transition.

    + +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:__CargoDeployed(Delay, TaskUnit, Cargo, DeployZone) + +
    +
    + +

    Asynchronous Event Trigger for Event CargoDeployed.

    + +

    Parameters

    +
      +
    • + +

      #number Delay : +The delay in seconds.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that Deployed the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    • + +

      Core.Zone#ZONE DeployZone : +The zone where the Cargo got Deployed or UnBoarded.

      + +
    • +
    +
    +
    +
    +
    + + +TASK_CARGO_TRANSPORT:__CargoPickedUp(Delay, TaskUnit, Cargo) + +
    +
    + +

    Asynchronous Event Trigger for Event CargoPickedUp.

    + +

    Parameters

    +
      +
    • + +

      #number Delay : +The delay in seconds.

      + +
    • +
    • + +

      Wrapper.Unit#UNIT TaskUnit : +The Unit (Client) that PickedUp the cargo. You can use this to retrieve the PlayerName etc.

      + +
    • +
    • + +

      Core.Cargo#CARGO Cargo : +The Cargo that got PickedUp by the TaskUnit. You can use this to check Cargo Status.

      + +
    • +
    diff --git a/docs/Documentation/Task_PICKUP.html b/docs/Documentation/Task_PICKUP.html index 3a8412d01..62f018d83 100644 --- a/docs/Documentation/Task_PICKUP.html +++ b/docs/Documentation/Task_PICKUP.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/Unit.html b/docs/Documentation/Unit.html index 3ab810188..9c4cba55e 100644 --- a/docs/Documentation/Unit.html +++ b/docs/Documentation/Unit.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/Utils.html b/docs/Documentation/Utils.html index 406805680..466bf943c 100644 --- a/docs/Documentation/Utils.html +++ b/docs/Documentation/Utils.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/Zone.html b/docs/Documentation/Zone.html index b9f59126b..d29a1c796 100644 --- a/docs/Documentation/Zone.html +++ b/docs/Documentation/Zone.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/env.html b/docs/Documentation/env.html index d5bc129b9..cb57d1c5c 100644 --- a/docs/Documentation/env.html +++ b/docs/Documentation/env.html @@ -17,6 +17,7 @@ index
      +
    • AI_BAI
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index 5487299fe..5766ea5a2 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -17,6 +17,7 @@ index
    @@ -2528,9 +2531,6 @@ when nothing was spawned.

    - -

    Overwrite unit names by default with group name.

    -
    @@ -2545,9 +2545,6 @@ when nothing was spawned.

    - -

    By default, no InitLimit

    -
    @@ -2583,7 +2580,7 @@ when nothing was spawned.

    - #number + SPAWN.SpawnMaxGroups @@ -2600,7 +2597,7 @@ when nothing was spawned.

    - #number + SPAWN.SpawnMaxUnitsAlive @@ -2952,7 +2949,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -

    Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.

    +

    When the first Spawn executes, all the Groups need to be made visible before start.

    @@ -3518,6 +3515,20 @@ True = Continue Scheduler

    + +
    +
    +
    + + + +SPAWN.uncontrolled + +
    +
    + + +
    diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index acc195246..1ee972150 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -762,7 +762,6 @@ true if it is lasing

    - SPOT.ScheduleID @@ -776,7 +775,6 @@ true if it is lasing

    - SPOT.SpotIR @@ -790,7 +788,6 @@ true if it is lasing

    - SPOT.SpotLaser @@ -804,7 +801,6 @@ true if it is lasing

    - SPOT.Target diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 5cb0f06fd..7b5964a17 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -502,7 +502,7 @@ based on the tasking capabilities defined in Task#TA
    - + Core.Cargo#CARGO FSM_PROCESS.Cargo diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index 5766ea5a2..9255879bf 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -99,7 +99,7 @@ AI_BAI -

    AI -- Provide Battleground Air Interdiction (bombing).

    +

    AI -- Provide Battlefield Air Interdiction (bombing).

    Banner Image

    From d4aa91300d33cdaca4faeb82b9644fd03fc3328b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 10 May 2017 09:52:11 +0200 Subject: [PATCH 19/32] Documentation updates --- docs/Documentation/AI_BAI.html | 2 +- docs/Documentation/AI_Patrol.html | 3 +++ docs/Documentation/Cargo.html | 1 - docs/Documentation/Point.html | 1 - docs/Documentation/Spawn.html | 24 ++---------------------- docs/Documentation/Spot.html | 4 ++++ docs/Documentation/Task_Cargo.html | 2 +- 7 files changed, 11 insertions(+), 26 deletions(-) diff --git a/docs/Documentation/AI_BAI.html b/docs/Documentation/AI_BAI.html index 3c74b363d..dfcc85f6b 100644 --- a/docs/Documentation/AI_BAI.html +++ b/docs/Documentation/AI_BAI.html @@ -560,7 +560,7 @@ It can be notified to go RTB through the RTB event.

    3. Modify the Engage Zone behaviour to pinpoint a map object or scenery object

    -

    Use the method AIBAIZONE.SearchOff() to specify that the EngageZone is not to be searched for potential targets (units), but that the center of the zone +

    Use the method AIBAIZONE.SearchOff() to specify that the EngageZone is not to be searched for potential targets (UNITs), but that the center of the zone is the point where a map object is to be destroyed (like a bridge).

    Example:

    diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index ab0dc233e..c9beaaa77 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -952,6 +952,9 @@ Use the method AIPATROLZONE.M + +

    This table contains the targets detected during patrol.

    +
    diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 0b2f68352..ed5f7adcd 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -3045,7 +3045,6 @@ The range till cargo will board.

    - #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/Point.html b/docs/Documentation/Point.html index d487eeafe..b48995723 100644 --- a/docs/Documentation/Point.html +++ b/docs/Documentation/Point.html @@ -1972,7 +1972,6 @@ The new calculated POINT_VEC2.

    - POINT_VEC2.z diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 1d8d862f2..3f656c930 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -771,12 +771,6 @@ and any spaces before and after the resulting name are removed.

    SPAWN:_TranslateRotate(SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle) - - - - SPAWN.uncontrolled - - @@ -2925,7 +2919,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
    - #boolean + SPAWN.SpawnUnControlled @@ -2949,7 +2943,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -

    When the first Spawn executes, all the Groups need to be made visible before start.

    +

    Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.

    @@ -3515,20 +3509,6 @@ True = Continue Scheduler

    - -
    -
    -
    - - - -SPAWN.uncontrolled - -
    -
    - - -
    diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index 1ee972150..acc195246 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -762,6 +762,7 @@ true if it is lasing

    + SPOT.ScheduleID @@ -775,6 +776,7 @@ true if it is lasing

    + SPOT.SpotIR @@ -788,6 +790,7 @@ true if it is lasing

    + SPOT.SpotLaser @@ -801,6 +804,7 @@ true if it is lasing

    + SPOT.Target diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 7b5964a17..5cb0f06fd 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -502,7 +502,7 @@ based on the tasking capabilities defined in Task#TA
    - Core.Cargo#CARGO + FSM_PROCESS.Cargo From b9c51ffc758cc07e6a9c91c35f4179619a6bc40f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 10 May 2017 10:33:23 +0200 Subject: [PATCH 20/32] Release of AI_FORMATION --- Moose Development/Moose/AI/AI_CAS.lua | 13 - Moose Development/Moose/AI/AI_Formation.lua | 305 +++++++++ Moose Mission Setup/Moose.files | 1 + Moose Mission Setup/Moose.lua | 3 +- docs/Documentation/AI_BAI.html | 1 + docs/Documentation/AI_Balancer.html | 1 + docs/Documentation/AI_Cap.html | 1 + docs/Documentation/AI_Cas.html | 16 +- docs/Documentation/AI_Follow.html | 670 ++++++++++++++++++++ docs/Documentation/AI_Patrol.html | 4 +- docs/Documentation/Account.html | 1 + docs/Documentation/Airbase.html | 1 + docs/Documentation/AirbasePolice.html | 1 + docs/Documentation/Assign.html | 1 + docs/Documentation/Base.html | 1 + docs/Documentation/Cargo.html | 2 + docs/Documentation/CleanUp.html | 1 + docs/Documentation/Client.html | 1 + docs/Documentation/CommandCenter.html | 1 + docs/Documentation/Controllable.html | 1 + docs/Documentation/DCSAirbase.html | 1 + docs/Documentation/DCSCoalitionObject.html | 1 + docs/Documentation/DCSCommand.html | 1 + docs/Documentation/DCSController.html | 1 + docs/Documentation/DCSGroup.html | 1 + docs/Documentation/DCSObject.html | 1 + docs/Documentation/DCSTask.html | 1 + docs/Documentation/DCSTypes.html | 1 + docs/Documentation/DCSUnit.html | 1 + docs/Documentation/DCSVec3.html | 1 + docs/Documentation/DCSWorld.html | 1 + docs/Documentation/DCSZone.html | 1 + docs/Documentation/DCScountry.html | 1 + docs/Documentation/DCStimer.html | 1 + docs/Documentation/DCStrigger.html | 1 + docs/Documentation/Database.html | 1 + docs/Documentation/Designate.html | 2 +- docs/Documentation/Detection.html | 4 +- docs/Documentation/DetectionManager.html | 1 + docs/Documentation/Escort.html | 1 + docs/Documentation/Event.html | 1 + docs/Documentation/Fsm.html | 1 + docs/Documentation/Group.html | 1 + docs/Documentation/Identifiable.html | 1 + docs/Documentation/Menu.html | 1 + docs/Documentation/Message.html | 1 + docs/Documentation/MissileTrainer.html | 1 + docs/Documentation/Mission.html | 1 + docs/Documentation/Movement.html | 5 +- docs/Documentation/Object.html | 1 + docs/Documentation/Point.html | 2 + docs/Documentation/Positionable.html | 1 + docs/Documentation/Process_JTAC.html | 1 + docs/Documentation/Process_Pickup.html | 1 + docs/Documentation/Radio.html | 1 + docs/Documentation/Route.html | 1 + docs/Documentation/Scenery.html | 1 + docs/Documentation/ScheduleDispatcher.html | 1 + docs/Documentation/Scheduler.html | 1 + docs/Documentation/Scoring.html | 1 + docs/Documentation/Sead.html | 1 + docs/Documentation/Set.html | 1 + docs/Documentation/Smoke.html | 1 + docs/Documentation/Spawn.html | 14 +- docs/Documentation/SpawnStatic.html | 2 + docs/Documentation/Spot.html | 1 + docs/Documentation/Static.html | 1 + docs/Documentation/StaticObject.html | 1 + docs/Documentation/Task.html | 1 + docs/Documentation/Task_A2G.html | 1 + docs/Documentation/Task_A2G_Dispatcher.html | 1 + docs/Documentation/Task_Cargo.html | 2 +- docs/Documentation/Task_PICKUP.html | 1 + docs/Documentation/Unit.html | 1 + docs/Documentation/Utils.html | 1 + docs/Documentation/Zone.html | 1 + docs/Documentation/env.html | 1 + docs/Documentation/index.html | 7 + docs/Documentation/land.html | 1 + docs/Documentation/routines.html | 1 + docs/Presentations/AI_FORMATION/Dia1.JPG | Bin 0 -> 172824 bytes 81 files changed, 1075 insertions(+), 41 deletions(-) create mode 100644 Moose Development/Moose/AI/AI_Formation.lua create mode 100644 docs/Documentation/AI_Follow.html create mode 100644 docs/Presentations/AI_FORMATION/Dia1.JPG diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index b9f866f0e..8e9eb20f6 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -28,19 +28,6 @@ -- -- === -- --- # **API CHANGE HISTORY** --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2017-01-15: Initial class and API. --- --- === --- -- # **AUTHORS and CONTRIBUTIONS** -- -- ### Contributions: diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua new file mode 100644 index 000000000..7440eeaf9 --- /dev/null +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -0,0 +1,305 @@ +--- **AI** -- (R2.1) Build large **formations** of AI @{Group}s flying together. +-- +-- ![Banner Image](..\Presentations\AI_FORMATION\Dia1.JPG) +-- +-- === +-- +-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. +-- +-- There are the following types of classes defined: +-- +-- * @{#AI_FORMATION}: Create a formation from several @{GROUP}s. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [AI_FORMATION Demo Missions source code]() +-- +-- ### [AI_FORMATION Demo Missions, only for beta testers]() +-- +-- ### [ALL Demo Missions pack of the last release]() +-- +-- ==== +-- +-- # YouTube Channel +-- +--- ### [AI_FORMATION YouTube Channel]() +-- +-- === +-- +-- # **AUTHORS and CONTRIBUTIONS** +-- +-- ### Contributions: +-- +-- ### Authors: +-- +-- * **FlightControl**: Concept, Design & Programming. +-- +-- @module AI_Follow + +--- AI_FORMATION class +-- @type AI_FORMATION +-- @extends Fsm#FSM_SET +-- @field Unit#UNIT FollowUnit +-- @field Set#SET_GROUP FollowGroupSet +-- @field #string FollowName +-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in. +-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class. +-- @field #number FollowDistance The current follow distance. +-- @field #boolean ReportTargets If true, nearby targets are reported. +-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup. +-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup. +-- @field Menu#MENU_CLIENT FollowMenuResumeMission + + +--- # AI_FORMATION class, extends @{Fsm#FSM_SET} +-- +-- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader. +-- +-- ## AI_FORMATION construction +-- +-- Create a new SPAWN object with the @{#AI_FORMATION.New} method: +-- +-- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Group#GROUP} for a @{Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text. +-- +-- ## Initialization methods +-- +-- The following menus are created within the RADIO MENU of an active unit hosted by a player: +-- +-- * @{Follow#AI_FORMATION.SetFormation}(): Set a Vec3 position for a GroupName within the GroupSet following. +-- +-- @usage +-- -- Declare a new FollowPlanes object as follows: +-- +-- -- First find the GROUP object and the CLIENT object. +-- local FollowUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. +-- local FollowGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Follow Client. +-- +-- -- Now use these 2 objects to construct the new FollowPlanes object. +-- FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +-- +-- @field #AI_FORMATION +AI_FORMATION = { + ClassName = "AI_FORMATION", + FollowName = nil, -- The Follow Name + FollowUnit = nil, + FollowGroupSet = nil, + FollowMode = 1, + MODE = { + FOLLOW = 1, + MISSION = 2, + }, + FollowScheduler = nil, + OptionROE = AI.Option.Air.val.ROE.OPEN_FIRE, + OptionReactionOnThreat = AI.Option.Air.val.REACTION_ON_THREAT.ALLOW_ABORT_MISSION, +} + +--- AI_FORMATION.Mode class +-- @type AI_FORMATION.MODE +-- @field #number FOLLOW +-- @field #number MISSION + +--- MENUPARAM type +-- @type MENUPARAM +-- @field #AI_FORMATION ParamSelf +-- @field #Distance ParamDistance +-- @field #function ParamFunction +-- @field #string ParamMessage + +--- AI_FORMATION class constructor for an AI group +-- @param #AI_FORMATION self +-- @param Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet. +-- @param Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string FollowName Name of the escort. +-- @return #AI_FORMATION self +function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefing ) + local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) ) + self:F( { FollowUnit, FollowGroupSet, FollowName } ) + + self.FollowUnit = FollowUnit -- Unit#UNIT + self.FollowGroupSet = FollowGroupSet -- Set#SET_GROUP + + self:SetStartState( "None" ) + + self:AddTransition( "*", "Stop", "Stopped" ) + + self:AddTransition( "None", "Start", "Following" ) + + self:AddTransition( "*", "Follow", "Following" ) + + FollowGroupSet:ForEachGroup( + --- @param Group#GROUP FollowGroup + function( FollowGroup, FollowName, FollowUnit ) + local Vec3 = { x = math.random( -20, -150 ), y = math.random( -50, 50 ), z = math.random( -800, 800 ) } + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + --FollowGroup:MessageToClient( FollowGroup:GetCategoryName() .. " '" .. FollowName .. "' (" .. FollowGroup:GetCallsign() .. ") reporting! " .. + -- "We're following your flight. ", + -- 60, FollowUnit + --) + end, + FollowName, self.FollowUnit + ) + + + self.FollowName = FollowName + self.FollowBriefing = FollowBriefing + + + self.CT1 = 0 + self.GT1 = 0 + + self.FollowMode = AI_FORMATION.MODE.MISSION + + return self +end + +--- This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to. +-- This allows to visualize where the escort is flying to. +-- @param #AI_FORMATION self +-- @param #boolean SmokeDirection If true, then the direction vector will be smoked. +function AI_FORMATION:TestSmokeDirectionVector( SmokeDirection ) + self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false + return self +end + + +--- @param Follow#AI_FORMATION self +function AI_FORMATION:onenterFollowing( FollowGroupSet ) + self:F( ) + + self:T( { self.FollowUnit.UnitName, self.FollowUnit:IsAlive() } ) + if self.FollowUnit:IsAlive() then + + local ClientUnit = self.FollowUnit + + self:T( {ClientUnit.UnitName } ) + + local CT1, CT2, CV1, CV2 + CT1 = ClientUnit:GetState( self, "CT1" ) + + if CT1 == nil or CT1 == 0 then + ClientUnit:SetState( self, "CV1", ClientUnit:GetPointVec3() ) + ClientUnit:SetState( self, "CT1", timer.getTime() ) + else + CT1 = ClientUnit:GetState( self, "CT1" ) + CT2 = timer.getTime() + CV1 = ClientUnit:GetState( self, "CV1" ) + CV2 = ClientUnit:GetPointVec3() + + ClientUnit:SetState( self, "CT1", CT2 ) + ClientUnit:SetState( self, "CV1", CV2 ) + end + + FollowGroupSet:ForEachGroup( + --- @param Group#GROUP FollowGroup + -- @param Unit#UNIT ClientUnit + function( FollowGroup, ClientUnit, CT1, CV1, CT2, CV2 ) + + local GroupUnit = FollowGroup:GetUnit( 1 ) + local FollowFormation = FollowGroup:GetState( self, "Vec3" ) + self:T( FollowFormation ) + local FollowDistance = FollowFormation.x + + self:T( {ClientUnit.UnitName, GroupUnit.UnitName } ) + + local GT1 = GroupUnit:GetState( self, "GT1" ) + + if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then + GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() ) + GroupUnit:SetState( self, "GT1", timer.getTime() ) + else + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 + local CT = CT2 - CT1 + + local CS = ( 3600 / CT ) * ( CD / 1000 ) + + self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + + local GT1 = GroupUnit:GetState( self, "GT1" ) + local GT2 = timer.getTime() + local GV1 = GroupUnit:GetState( self, "GV1" ) + local GV2 = GroupUnit:GetPointVec3() + GroupUnit:SetState( self, "GT1", GT2 ) + GroupUnit:SetState( self, "GV1", GV2 ) + + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 + local GT = GT2 - GT1 + + local GS = ( 3600 / GT ) * ( GD / 1000 ) + + self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) + + -- Calculate the group direction vector + local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } + + -- Calculate GH2, GH2 with the same height as CV2. + local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } + + -- Calculate the angle of GV to the orthonormal plane + local alpha = math.atan2( GV.z, GV.x ) + + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) + local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + y = GH2.y + FollowFormation.y, + z = CV2.z + FollowDistance * math.sin(alpha), + } + + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. + local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } + + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. + -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. + -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... + local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } + + -- Now we can calculate the group destination vector GDV. + local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } + + local GDV_Formation = { + x = GDV.x + ( FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha) ), + y = GDV.y, + z = GDV.z + ( FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha) ) + } + + if self.SmokeDirectionVector == true then + trigger.action.smoke( GDV, trigger.smokeColor.Green ) + trigger.action.smoke( GDV_Formation, trigger.smokeColor.White ) + end + + self:T3( { "CV2:", CV2 } ) + self:T3( { "CVI:", CVI } ) + self:T2( { "GDV:", GDV } ) + + -- Measure distance between client and group + local CatchUpDistance = ( ( GDV_Formation.x - GV2.x )^2 + ( GDV_Formation.y - GV2.y )^2 + ( GDV_Formation.z - GV2.z )^2 ) ^ 0.5 + + -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome + -- the requested Distance). + local Time = 20 + local CatchUpSpeed = ( CatchUpDistance - ( CS * 9.5 ) ) / Time + + local Speed = CS + CatchUpSpeed + if Speed < 0 then + Speed = 0 + end + + self:T({CatchUpDistance, CatchUpSpeed}) + + self:T3( { "Client Speed, Follow Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } ) + + -- Now route the escort to the desired point with the desired speed. + FollowGroup:RouteToVec3( GDV_Formation, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) + end + end, + ClientUnit, CT1, CV1, CT2, CV2 + ) + + self:__Follow( -0.5 ) + end + +end + diff --git a/Moose Mission Setup/Moose.files b/Moose Mission Setup/Moose.files index 6cc1565c1..5d8c15212 100644 --- a/Moose Mission Setup/Moose.files +++ b/Moose Mission Setup/Moose.files @@ -44,6 +44,7 @@ AI/AI_Patrol.lua AI/AI_Cap.lua AI/AI_Cas.lua AI/AI_Bai.lua +AI/AI_Formation.lua Actions/Act_Assign.lua Actions/Act_Route.lua diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 241147a4e..ef7a6b0b3 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170509_2025' ) +env.info( 'Moose Generation Timestamp: 20170510_1031' ) local base = _G @@ -63,6 +63,7 @@ __Moose.Include( 'AI/AI_Patrol.lua' ) __Moose.Include( 'AI/AI_Cap.lua' ) __Moose.Include( 'AI/AI_Cas.lua' ) __Moose.Include( 'AI/AI_Bai.lua' ) +__Moose.Include( 'AI/AI_Formation.lua' ) __Moose.Include( 'Actions/Act_Assign.lua' ) __Moose.Include( 'Actions/Act_Route.lua' ) __Moose.Include( 'Actions/Act_Account.lua' ) diff --git a/docs/Documentation/AI_BAI.html b/docs/Documentation/AI_BAI.html index dfcc85f6b..fcf7e478e 100644 --- a/docs/Documentation/AI_BAI.html +++ b/docs/Documentation/AI_BAI.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 8230fd694..412cda7ff 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/AI_Cap.html b/docs/Documentation/AI_Cap.html index a87487c58..c8385d7ae 100644 --- a/docs/Documentation/AI_Cap.html +++ b/docs/Documentation/AI_Cap.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/AI_Cas.html b/docs/Documentation/AI_Cas.html index f99458bb4..6a7fe4211 100644 --- a/docs/Documentation/AI_Cas.html +++ b/docs/Documentation/AI_Cas.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -130,21 +131,6 @@
    -

    API CHANGE HISTORY

    - -

    The underlying change log documents the API changes. Please read this carefully. The following notation is used:

    - -
      -
    • Added parts are expressed in bold type face.
    • -
    • Removed parts are expressed in italic type face.
    • -
    - -

    Hereby the change log:

    - -

    2017-01-15: Initial class and API.

    - -
    -

    AUTHORS and CONTRIBUTIONS

    Contributions:

    diff --git a/docs/Documentation/AI_Follow.html b/docs/Documentation/AI_Follow.html new file mode 100644 index 000000000..7cd88cbc5 --- /dev/null +++ b/docs/Documentation/AI_Follow.html @@ -0,0 +1,670 @@ + + + + + + +
    +
    + +
    +
    +
    +
    + +
    +

    Module AI_Follow

    + +

    AI -- (R2.1) Build large formations of AI Groups flying together.

    + + + +

    Banner Image

    + +
    + +

    AI_FORMATION makes AI GROUPs fly in formation of various compositions.

    + +

    There are the following types of classes defined:

    + + + +
    + +

    Demo Missions

    + +

    AI_FORMATION Demo Missions source code

    + +

    AI_FORMATION Demo Missions, only for beta testers

    + +

    ALL Demo Missions pack of the last release

    + +
    + +

    YouTube Channel

    + + + +
    + +

    AUTHORS and CONTRIBUTIONS

    + +

    Contributions:

    + +

    Authors:

    + +
      +
    • FlightControl: Concept, Design & Programming. +
    • +
    + +

    Global(s)

    + + + + + +
    AI_FORMATION +

    AI_FORMATION class, extends Fsm#FSM_SET

    + +

    The #AI_FORMATION class allows you to build large formations, make AI follow a Client#CLIENT (player) leader or a Unit#UNIT (AI) leader.

    +
    +

    Type AI_FORMATION

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AI_FORMATION.FollowDistance +

    The current follow distance.

    +
    AI_FORMATION.FollowGroupSet + +
    AI_FORMATION.FollowMenuResumeMission + +
    AI_FORMATION.FollowMode +

    The mode the escort is in.

    +
    AI_FORMATION.FollowName + +
    AI_FORMATION.FollowScheduler +

    The instance of the SCHEDULER class.

    +
    AI_FORMATION.FollowUnit + +
    AI_FORMATION:New(FollowUnit, FollowGroupSet, FollowName, FollowBriefing) +

    AI_FORMATION class constructor for an AI group

    +
    AI_FORMATION.OptionReactionOnThreat +

    Which REACTIONONTHREAT is set to the FollowGroup.

    +
    AI_FORMATION.ReportTargets +

    If true, nearby targets are reported.

    +
    AI_FORMATION.SmokeDirectionVector + +
    AI_FORMATION:TestSmokeDirectionVector(SmokeDirection) +

    This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.

    +
    AI_FORMATION:onenterFollowing(FollowGroupSet) + +
    + +

    Type AI_FORMATION.MODE

    + + + + + + + + + +
    AI_FORMATION.MODE.FOLLOW + +
    AI_FORMATION.MODE.MISSION + +
    + +

    Type MENUPARAM

    + + + + + + + + + + + + + + + + + +
    MENUPARAM.ParamDistance + +
    MENUPARAM.ParamFunction + +
    MENUPARAM.ParamMessage + +
    MENUPARAM.ParamSelf + +
    + +

    Global(s)

    +
    +
    + + #AI_FORMATION + +AI_FORMATION + +
    +
    + +

    AI_FORMATION class, extends Fsm#FSM_SET

    + +

    The #AI_FORMATION class allows you to build large formations, make AI follow a Client#CLIENT (player) leader or a Unit#UNIT (AI) leader.

    + + + +

    AI_FORMATION construction

    + +

    Create a new SPAWN object with the AI_FORMATION.New method:

    + + + +

    Initialization methods

    + +

    The following menus are created within the RADIO MENU of an active unit hosted by a player:

    + + + + +

    Usage:

    +
    -- Declare a new FollowPlanes object as follows:
    +
    +-- First find the GROUP object and the CLIENT object.
    +local FollowUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
    +local FollowGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Follow Client.
    +
    +-- Now use these 2 objects to construct the new FollowPlanes object.
    +FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
    +
    + +
    +
    +

    Type AI_Follow

    + +

    Type AI_FORMATION

    + +

    AI_FORMATION class

    + +

    Field(s)

    +
    +
    + + #number + +AI_FORMATION.FollowDistance + +
    +
    + +

    The current follow distance.

    + +
    +
    +
    +
    + + Set#SET_GROUP + +AI_FORMATION.FollowGroupSet + +
    +
    + + + +
    +
    +
    +
    + + Menu#MENU_CLIENT + +AI_FORMATION.FollowMenuResumeMission + +
    +
    + + + +
    +
    +
    +
    + + #AI_FORMATION.MODE + +AI_FORMATION.FollowMode + +
    +
    + +

    The mode the escort is in.

    + +
    +
    +
    +
    + + #string + +AI_FORMATION.FollowName + +
    +
    + + + +
    +
    +
    +
    + + Scheduler#SCHEDULER + +AI_FORMATION.FollowScheduler + +
    +
    + +

    The instance of the SCHEDULER class.

    + +
    +
    +
    +
    + + Unit#UNIT + +AI_FORMATION.FollowUnit + +
    +
    + + + +
    +
    +
    +
    + + +AI_FORMATION:New(FollowUnit, FollowGroupSet, FollowName, FollowBriefing) + +
    +
    + +

    AI_FORMATION class constructor for an AI group

    + +

    Parameters

    +
      +
    • + +

      Unit#UNIT FollowUnit : +The UNIT leading the FolllowGroupSet.

      + +
    • +
    • + +

      Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string FollowName : +Name of the escort.

      + +
    • +
    • + +

      FollowBriefing :

      + +
    • +
    +

    Return value

    + +

    #AI_FORMATION: +self

    + +
    +
    +
    +
    + + DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT + +AI_FORMATION.OptionReactionOnThreat + +
    +
    + +

    Which REACTIONONTHREAT is set to the FollowGroup.

    + +
    +
    +
    +
    + + #boolean + +AI_FORMATION.ReportTargets + +
    +
    + +

    If true, nearby targets are reported.

    + +
    +
    +
    +
    + + +AI_FORMATION.SmokeDirectionVector + +
    +
    + + + +
    +
    +
    +
    + + +AI_FORMATION:TestSmokeDirectionVector(SmokeDirection) + +
    +
    + +

    This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.

    + + +

    This allows to visualize where the escort is flying to.

    + +

    Parameter

    +
      +
    • + +

      #boolean SmokeDirection : +If true, then the direction vector will be smoked.

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:onenterFollowing(FollowGroupSet) + +
    +
    + + + +

    Parameter

    +
      +
    • + +

      FollowGroupSet :

      + +
    • +
    +
    +
    + +

    Type AI_FORMATION.MODE

    + +

    AI_FORMATION.Mode class

    + +

    Field(s)

    +
    +
    + + #number + +AI_FORMATION.MODE.FOLLOW + +
    +
    + + + +
    +
    +
    +
    + + #number + +AI_FORMATION.MODE.MISSION + +
    +
    + + + +
    +
    + +

    Type Distance

    + +

    Type MENUPARAM

    + +

    MENUPARAM type

    + +

    Field(s)

    +
    +
    + + #Distance + +MENUPARAM.ParamDistance + +
    +
    + + + +
    +
    +
    +
    + + #function + +MENUPARAM.ParamFunction + +
    +
    + + + +
    +
    +
    +
    + + #string + +MENUPARAM.ParamMessage + +
    +
    + + + +
    +
    +
    +
    + + #AI_FORMATION + +MENUPARAM.ParamSelf + +
    +
    + + + +
    +
    + +
    + +
    + + diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index c9beaaa77..bebc26831 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -952,9 +953,6 @@ Use the method AIPATROLZONE.M - -

    This table contains the targets detected during patrol.

    -
    diff --git a/docs/Documentation/Account.html b/docs/Documentation/Account.html index 40cca1764..c9525a456 100644 --- a/docs/Documentation/Account.html +++ b/docs/Documentation/Account.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Airbase.html b/docs/Documentation/Airbase.html index 439ea2f1b..d34c31236 100644 --- a/docs/Documentation/Airbase.html +++ b/docs/Documentation/Airbase.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/AirbasePolice.html b/docs/Documentation/AirbasePolice.html index 8a03b3a59..4b588bf42 100644 --- a/docs/Documentation/AirbasePolice.html +++ b/docs/Documentation/AirbasePolice.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Assign.html b/docs/Documentation/Assign.html index 1565398e5..32c34434e 100644 --- a/docs/Documentation/Assign.html +++ b/docs/Documentation/Assign.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Base.html b/docs/Documentation/Base.html index 64657992b..78561eaa0 100644 --- a/docs/Documentation/Base.html +++ b/docs/Documentation/Base.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index ed5f7adcd..8fadae3b5 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -3045,6 +3046,7 @@ The range till cargo will board.

    + #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/CleanUp.html b/docs/Documentation/CleanUp.html index 3e5471b7e..61f906774 100644 --- a/docs/Documentation/CleanUp.html +++ b/docs/Documentation/CleanUp.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Client.html b/docs/Documentation/Client.html index 472bbe443..ee544737e 100644 --- a/docs/Documentation/Client.html +++ b/docs/Documentation/Client.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/CommandCenter.html b/docs/Documentation/CommandCenter.html index bcf88684a..68874808d 100644 --- a/docs/Documentation/CommandCenter.html +++ b/docs/Documentation/CommandCenter.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Controllable.html b/docs/Documentation/Controllable.html index c5abef460..393e9510c 100644 --- a/docs/Documentation/Controllable.html +++ b/docs/Documentation/Controllable.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSAirbase.html b/docs/Documentation/DCSAirbase.html index f9b40732f..1f853ff13 100644 --- a/docs/Documentation/DCSAirbase.html +++ b/docs/Documentation/DCSAirbase.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSCoalitionObject.html b/docs/Documentation/DCSCoalitionObject.html index 5d9721659..e4ff82a64 100644 --- a/docs/Documentation/DCSCoalitionObject.html +++ b/docs/Documentation/DCSCoalitionObject.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSCommand.html b/docs/Documentation/DCSCommand.html index 918aba934..ef4f5e1e3 100644 --- a/docs/Documentation/DCSCommand.html +++ b/docs/Documentation/DCSCommand.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSController.html b/docs/Documentation/DCSController.html index c8f091a16..e52b918e6 100644 --- a/docs/Documentation/DCSController.html +++ b/docs/Documentation/DCSController.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSGroup.html b/docs/Documentation/DCSGroup.html index f5cf0300e..bc74ae421 100644 --- a/docs/Documentation/DCSGroup.html +++ b/docs/Documentation/DCSGroup.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSObject.html b/docs/Documentation/DCSObject.html index aa771f73d..ffe8cd55c 100644 --- a/docs/Documentation/DCSObject.html +++ b/docs/Documentation/DCSObject.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSTask.html b/docs/Documentation/DCSTask.html index bdab8ced8..a398a5d0d 100644 --- a/docs/Documentation/DCSTask.html +++ b/docs/Documentation/DCSTask.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSTypes.html b/docs/Documentation/DCSTypes.html index 68b115ab2..d6eaf64ad 100644 --- a/docs/Documentation/DCSTypes.html +++ b/docs/Documentation/DCSTypes.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSUnit.html b/docs/Documentation/DCSUnit.html index ff49c3ce0..4d46d0b27 100644 --- a/docs/Documentation/DCSUnit.html +++ b/docs/Documentation/DCSUnit.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSVec3.html b/docs/Documentation/DCSVec3.html index bae815190..1bc44128c 100644 --- a/docs/Documentation/DCSVec3.html +++ b/docs/Documentation/DCSVec3.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSWorld.html b/docs/Documentation/DCSWorld.html index 8cf46e3e9..63d533748 100644 --- a/docs/Documentation/DCSWorld.html +++ b/docs/Documentation/DCSWorld.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCSZone.html b/docs/Documentation/DCSZone.html index dcfed9d0f..43bde0465 100644 --- a/docs/Documentation/DCSZone.html +++ b/docs/Documentation/DCSZone.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCScountry.html b/docs/Documentation/DCScountry.html index 3513b9812..e8ac8b2ac 100644 --- a/docs/Documentation/DCScountry.html +++ b/docs/Documentation/DCScountry.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCStimer.html b/docs/Documentation/DCStimer.html index 1822b7fbc..a58433496 100644 --- a/docs/Documentation/DCStimer.html +++ b/docs/Documentation/DCStimer.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/DCStrigger.html b/docs/Documentation/DCStrigger.html index 0a12a11e5..032bffd19 100644 --- a/docs/Documentation/DCStrigger.html +++ b/docs/Documentation/DCStrigger.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index 70294483b..08030f60c 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index 36af9145f..cf1f82b99 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -891,7 +892,6 @@ function below will use the range 1-7 just in case

    - DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 13499cb5c..62e57668f 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -2336,6 +2337,7 @@ The index of the DetectedItem.

    + #number DETECTION_BASE.DetectedItemMax @@ -2475,7 +2477,7 @@ The index of the DetectedItem.

    - + #number DETECTION_BASE.DetectionInterval diff --git a/docs/Documentation/DetectionManager.html b/docs/Documentation/DetectionManager.html index b5aea1316..8bd62d1ba 100644 --- a/docs/Documentation/DetectionManager.html +++ b/docs/Documentation/DetectionManager.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Escort.html b/docs/Documentation/Escort.html index a43ecab35..843d53fce 100644 --- a/docs/Documentation/Escort.html +++ b/docs/Documentation/Escort.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Event.html b/docs/Documentation/Event.html index bfa3823de..6970fd5c1 100644 --- a/docs/Documentation/Event.html +++ b/docs/Documentation/Event.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index a5360ca5f..f0ab48a01 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Group.html b/docs/Documentation/Group.html index d970725e0..d79e8fadd 100644 --- a/docs/Documentation/Group.html +++ b/docs/Documentation/Group.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Identifiable.html b/docs/Documentation/Identifiable.html index c049a8f65..bae17f2a7 100644 --- a/docs/Documentation/Identifiable.html +++ b/docs/Documentation/Identifiable.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Menu.html b/docs/Documentation/Menu.html index f294044d9..52ec6351c 100644 --- a/docs/Documentation/Menu.html +++ b/docs/Documentation/Menu.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Message.html b/docs/Documentation/Message.html index 3d8c4d78f..98d9b1abb 100644 --- a/docs/Documentation/Message.html +++ b/docs/Documentation/Message.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/MissileTrainer.html b/docs/Documentation/MissileTrainer.html index 88159742b..577940307 100644 --- a/docs/Documentation/MissileTrainer.html +++ b/docs/Documentation/MissileTrainer.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Mission.html b/docs/Documentation/Mission.html index fa18d7ec0..7a2b74f9f 100644 --- a/docs/Documentation/Mission.html +++ b/docs/Documentation/Mission.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index 3adb3bd89..c732cbe69 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -214,7 +215,6 @@ on defined intervals (currently every minute).

    - #number MOVEMENT.AliveUnits @@ -223,9 +223,6 @@ on defined intervals (currently every minute).

    - -

    Contains the counter how many units are currently alive

    -
    diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index 63145ee4b..04267f399 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Point.html b/docs/Documentation/Point.html index b48995723..1c346e107 100644 --- a/docs/Documentation/Point.html +++ b/docs/Documentation/Point.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -1972,6 +1973,7 @@ The new calculated POINT_VEC2.

    + POINT_VEC2.z diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index d9dea20e8..e1c48ea50 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Process_JTAC.html b/docs/Documentation/Process_JTAC.html index 9e073a5a6..9d4822e4e 100644 --- a/docs/Documentation/Process_JTAC.html +++ b/docs/Documentation/Process_JTAC.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Process_Pickup.html b/docs/Documentation/Process_Pickup.html index 20b6065b6..89446f104 100644 --- a/docs/Documentation/Process_Pickup.html +++ b/docs/Documentation/Process_Pickup.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Radio.html b/docs/Documentation/Radio.html index 74bfa4e8c..b6981c8fc 100644 --- a/docs/Documentation/Radio.html +++ b/docs/Documentation/Radio.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Route.html b/docs/Documentation/Route.html index 4b4f79333..e4083d4f2 100644 --- a/docs/Documentation/Route.html +++ b/docs/Documentation/Route.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Scenery.html b/docs/Documentation/Scenery.html index 114319f43..1e7bd21b3 100644 --- a/docs/Documentation/Scenery.html +++ b/docs/Documentation/Scenery.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/ScheduleDispatcher.html b/docs/Documentation/ScheduleDispatcher.html index c5292e224..92e5c48f6 100644 --- a/docs/Documentation/ScheduleDispatcher.html +++ b/docs/Documentation/ScheduleDispatcher.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Scheduler.html b/docs/Documentation/Scheduler.html index 7981b1438..99a06b956 100644 --- a/docs/Documentation/Scheduler.html +++ b/docs/Documentation/Scheduler.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Scoring.html b/docs/Documentation/Scoring.html index 322b24998..6254b8f94 100644 --- a/docs/Documentation/Scoring.html +++ b/docs/Documentation/Scoring.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Sead.html b/docs/Documentation/Sead.html index dbf3167ec..091a3a22c 100644 --- a/docs/Documentation/Sead.html +++ b/docs/Documentation/Sead.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Set.html b/docs/Documentation/Set.html index 56e79058a..0e9cfb62f 100644 --- a/docs/Documentation/Set.html +++ b/docs/Documentation/Set.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Smoke.html b/docs/Documentation/Smoke.html index 136d8ac61..68e79e26c 100644 --- a/docs/Documentation/Smoke.html +++ b/docs/Documentation/Smoke.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 3f656c930..4a10c8567 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -2072,6 +2073,9 @@ The group that was spawned. You can use this group for further actions.

    + +

    Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.

    +
    @@ -2525,6 +2529,9 @@ when nothing was spawned.

    + +

    Overwrite unit names by default with group name.

    +
    @@ -2539,6 +2546,9 @@ when nothing was spawned.

    + +

    By default, no InitLimit

    +
    @@ -2574,7 +2584,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxGroups @@ -2591,7 +2601,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxUnitsAlive diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index d1a622752..69a9412e9 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -445,6 +446,7 @@ ptional) The name of the new static.

    + #number SPAWNSTATIC.SpawnIndex diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index acc195246..5ddfdc1f0 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Static.html b/docs/Documentation/Static.html index ffa9fdb0e..60dac6185 100644 --- a/docs/Documentation/Static.html +++ b/docs/Documentation/Static.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/StaticObject.html b/docs/Documentation/StaticObject.html index b8eff3eed..805c6b594 100644 --- a/docs/Documentation/StaticObject.html +++ b/docs/Documentation/StaticObject.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Task.html b/docs/Documentation/Task.html index 32e192c3f..3391dc69b 100644 --- a/docs/Documentation/Task.html +++ b/docs/Documentation/Task.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Task_A2G.html b/docs/Documentation/Task_A2G.html index fd355500d..b6c3d97ad 100644 --- a/docs/Documentation/Task_A2G.html +++ b/docs/Documentation/Task_A2G.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Task_A2G_Dispatcher.html b/docs/Documentation/Task_A2G_Dispatcher.html index 54ba3cfa4..b6a81e7b3 100644 --- a/docs/Documentation/Task_A2G_Dispatcher.html +++ b/docs/Documentation/Task_A2G_Dispatcher.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 5cb0f06fd..5c03c9d31 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -516,7 +517,6 @@ based on the tasking capabilities defined in Task#TA
    - FSM_PROCESS.DeployZone diff --git a/docs/Documentation/Task_PICKUP.html b/docs/Documentation/Task_PICKUP.html index 62f018d83..ab9a92d05 100644 --- a/docs/Documentation/Task_PICKUP.html +++ b/docs/Documentation/Task_PICKUP.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Unit.html b/docs/Documentation/Unit.html index 9c4cba55e..44b0bccac 100644 --- a/docs/Documentation/Unit.html +++ b/docs/Documentation/Unit.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Utils.html b/docs/Documentation/Utils.html index 466bf943c..28412ed44 100644 --- a/docs/Documentation/Utils.html +++ b/docs/Documentation/Utils.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/Zone.html b/docs/Documentation/Zone.html index d29a1c796..81af387d2 100644 --- a/docs/Documentation/Zone.html +++ b/docs/Documentation/Zone.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/env.html b/docs/Documentation/env.html index cb57d1c5c..94099292d 100644 --- a/docs/Documentation/env.html +++ b/docs/Documentation/env.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index 9255879bf..e6e185419 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • @@ -162,6 +163,12 @@ even when there are hardly any players in the mission.


    AI CAS classes makes AI Controllables execute a Close Air Support.

    + + + + AI_Follow + +

    AI -- (R2.1) Build large formations of AI Groups flying together.

    diff --git a/docs/Documentation/land.html b/docs/Documentation/land.html index 9d747a907..64ee55186 100644 --- a/docs/Documentation/land.html +++ b/docs/Documentation/land.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Documentation/routines.html b/docs/Documentation/routines.html index e497edb3a..8577991c4 100644 --- a/docs/Documentation/routines.html +++ b/docs/Documentation/routines.html @@ -21,6 +21,7 @@
  • AI_Balancer
  • AI_Cap
  • AI_Cas
  • +
  • AI_Follow
  • AI_Patrol
  • Account
  • Airbase
  • diff --git a/docs/Presentations/AI_FORMATION/Dia1.JPG b/docs/Presentations/AI_FORMATION/Dia1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..a4edad01b99f16ac6dc1c4a10275046ea363d9af GIT binary patch literal 172824 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%0AZ)$U}wXbt9c2of|DY{u|Yb>~MfIzlN^!O@lov z>{rYp^9W91wKj^H%)dKk-^dRuSL7sql1sUFv0F#`cTO5ds@IU6>~+X3%lUWP?byR^ zZ}saxhcNIO##-w<;b_*vv;%2qKBhF}C4QEqguPJy`oY!Hx8z5!h<2DmvHc3?lIjcM zj4~Ptn$Y!>eJ36hPUC=v#YtwU3sh`*x=`I9W76k1DW&xWVs&xJfmHfT1^hvQ@uTN9 z+w;HZ0#PQ^$4GsW2foV|I#Rz`{TktP&}f~N0O<|!;d_>>`HNi?>A~?`VDv7i*pj@y zY!G3zxC}rS`r~vwsuOWwwjN~!Bq5%&hHK@BQWjcIzucO7!6fGZ7B+U!2v}%6-D}8! zmj*b_pcnXs#(CFT#B#GiJ+>mBD})a?dO|}+vMUc)n)%A_)qvO_8G2Xr%dxm0z5Tty zM?(xTWnDMVH;S;-o=UUG4&tYtSl1_@Rh7}b;KY*!Ipcxb%4H&csR)T;nNEZBLCPZ( z1jfo|ey|SKt?Q?^W={p`*bju_LrclBBy|ugNoDZd%p?1vV`SWGpGiVmcR8P~A&QZc z{V{0P9P^}wlPI9WykaWC%&57aO{S_4RFGsRgru%%y4#=>bstHZpQgkVr8gaYUuN%R- zB5{E3$>BpR_jcVgc-U;J7aaX$GD&u69jIL+f;N`bUVAp|IT%hqH$6H0i%uqeq&wi& z%kS!w47-`=0ptlKPG81Sosm?zJnxk`Q2RMF)okaYNF4P6Cgt5yT7s1=8Cqt!(9U94J#xUg zAHZMF{@LVtQTyqkZQ1FdpF`xprb_L%Ru%LkyG?S=;_yeeBu5u>Sc^BM(tM^y%#?tM z@TpNd`Mpei+a^R-TC>7%v02RasSQ_Z@TU2@#{e?8)3FzRs22{sZm@FqtDP&i=IaWT zYnwDsG;)lTRIAo3p6~~&g(&AHpAGHm3F0$;jW<2gMbc+7(cNIutcv2Xua5g=f13jG zy;uGi*ffx(n*WxWa=Gfhj&!6Mo_Slh12C;9#Q$ziJ80pek&P*!67>&2;_^=c%28oe zWw>%>KtNcx#mYeCs&|t@$Vaa^<1*mHYXMbQJ41!7ZJk0}X8*Xv)zG%L_!r%TRnDb# z?9~s5lfR{?Pzmxw3Y(xh-T_r!aJ{?S{7a&UVdORMn3hhJZikccnM|KCTiju7$|0rY z$H2a|v|aK8Wl=>$tDA?v8?2o5Q;5m(Awe

      *X)*^d7@@HQ7ys;g&=bHPHvevS>Sy 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 Date: Thu, 11 May 2017 11:47:30 +0200 Subject: [PATCH 21/32] Working Version! --- Moose Development/Moose/AI/AI_Formation.lua | 494 ++++++++--- docs/Documentation/AI_Follow.html | 934 +++++++++++++++++++- docs/Documentation/AI_Patrol.html | 3 + docs/Documentation/Cargo.html | 1 - docs/Documentation/Detection.html | 1 - docs/Documentation/Fsm.html | 3 +- docs/Documentation/Movement.html | 4 + docs/Documentation/Spawn.html | 32 +- docs/Documentation/SpawnStatic.html | 1 - docs/Documentation/Task_Cargo.html | 2 +- 10 files changed, 1348 insertions(+), 127 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 7440eeaf9..d3a18880a 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -67,7 +67,15 @@ -- -- The following menus are created within the RADIO MENU of an active unit hosted by a player: -- --- * @{Follow#AI_FORMATION.SetFormation}(): Set a Vec3 position for a GroupName within the GroupSet following. +-- * @{AI_Formation#AI_FORMATION.FormationRandom}(): Form a randomized formation (can cause crashed of planes :-)). +-- * @{AI_Formation#AI_FORMATION.FormationLeftLine}(): Form a left line formation. +-- * @{AI_Formation#AI_FORMATION.FormationRightLine}(): Form a right line formation. +-- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation. +-- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation. +-- * @{AI_Formation#AI_FORMATION.FormationCenterLine}(): Form a center line formation. +-- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation. +-- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation. +-- -- -- @usage -- -- Declare a new FollowPlanes object as follows: @@ -110,7 +118,7 @@ AI_FORMATION = { --- AI_FORMATION class constructor for an AI group -- @param #AI_FORMATION self -- @param Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet. --- @param Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string FollowName Name of the escort. -- @return #AI_FORMATION self function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefing ) @@ -126,23 +134,151 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin self:AddTransition( "None", "Start", "Following" ) - self:AddTransition( "*", "Follow", "Following" ) + self:AddTransition( "*", "FormationLeftLine", "*" ) - FollowGroupSet:ForEachGroup( - --- @param Group#GROUP FollowGroup - function( FollowGroup, FollowName, FollowUnit ) - local Vec3 = { x = math.random( -20, -150 ), y = math.random( -50, 50 ), z = math.random( -800, 800 ) } - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() - --FollowGroup:MessageToClient( FollowGroup:GetCategoryName() .. " '" .. FollowName .. "' (" .. FollowGroup:GetCallsign() .. ") reporting! " .. - -- "We're following your flight. ", - -- 60, FollowUnit - --) - end, - FollowName, self.FollowUnit - ) + --- FormationLeftLine Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationLeftLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @return #boolean + + --- FormationLeftLine Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationLeftLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + + --- FormationLeftLine Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationLeftLine + -- @param #AI_FORMATION self + + --- FormationLeftLine Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationLeftLine + -- @param #AI_FORMATION self + -- @param #number Delay + + + self:AddTransition( "*", "FormationRightLine", "*" ) + + --- FormationRightLine Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationRightLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @return #boolean + + --- FormationRightLine Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationRightLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + + --- FormationRightLine Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationRightLine + -- @param #AI_FORMATION self + + --- FormationRightLine Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationRightLine + -- @param #AI_FORMATION self + -- @param #number Delay + + self:AddTransition( "*", "FormationLeftWing", "*" ) + + --- FormationLeftWing Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationLeftWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @return #boolean + + --- FormationLeftWing Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationLeftWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + + --- FormationLeftWing Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationLeftWing + -- @param #AI_FORMATION self + + --- FormationLeftWing Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationLeftWing + -- @param #AI_FORMATION self + -- @param #number Delay + + + self:AddTransition( "*", "FormationRightWing", "*" ) + + --- FormationRightWing Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationRightWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @return #boolean + + --- FormationRightWing Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationRightWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XSpace The space on the X-axis in meters between each group. + -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. + -- @param #number ZSpace The start position on the Z-axis in meters for each group. + + --- FormationRightWing Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationRightWing + -- @param #AI_FORMATION self + + --- FormationRightWing Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationRightWing + -- @param #AI_FORMATION self + -- @param #number Delay + + + + + + self:AddTransition( "*", "Follow", "Following" ) + self:FormationLeftLine( 50, 0, 100 ) self.FollowName = FollowName self.FollowBriefing = FollowBriefing @@ -160,11 +296,150 @@ end -- This allows to visualize where the escort is flying to. -- @param #AI_FORMATION self -- @param #boolean SmokeDirection If true, then the direction vector will be smoked. +-- @return #AI_FORMATION function AI_FORMATION:TestSmokeDirectionVector( SmokeDirection ) self.SmokeDirectionVector = ( SmokeDirection == true ) and true or false return self end +--- FormationLeftLine Handler OnAfter for AI_FORMATION +-- @function [parent=#AI_FORMATION] OnAfterFormationLeftLine +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XSpace The space on the X-axis in meters between each group. +-- @param #nubmer YSpace The start position on the Y-axis in meters for each group. +-- @param #number ZSpace The start position on the Z-axis in meters for each group. +function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) + self:E( { FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace } ) + + FollowGroupSet:Flush() + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + PointVec3:SetX( -XSpace ) + PointVec3:SetY( YSpace ) + PointVec3:SetZ( i * ZSpace ) + + local Vec3 = PointVec3:GetVec3() + self:E( Vec3 ) + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + i = i + 1 + end + +end + + +--- FormationRightLine Handler OnAfter for AI_FORMATION +-- @function [parent=#AI_FORMATION] OnAfterFormationLeftLine +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XSpace The space on the X-axis in meters between each group. +-- @param #nubmer YSpace The start position on the Y-axis in meters for each group. +-- @param #number ZSpace The start position on the Z-axis in meters for each group. +function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + PointVec3:SetX( i * XSpace ) + PointVec3:SetY( YSpace ) + PointVec3:SetZ( -ZSpace ) + + local Vec3 = PointVec3:GetVec3() + self:E( Vec3 ) + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + i = i + 1 + end + +end + + +--- FormationLeftWing Handler OnAfter for AI_FORMATION +-- @function [parent=#AI_FORMATION] OnAfterFormationLeftWing +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XSpace The space on the X-axis in meters between each group. +-- @param #nubmer YSpace The start position on the Y-axis in meters for each group. +-- @param #number ZSpace The start position on the Z-axis in meters for each group. +function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + PointVec3:SetX( -i * XSpace ) + PointVec3:SetY( i * YSpace ) + PointVec3:SetZ( -ZSpace ) + + local Vec3 = PointVec3:GetVec3() + self:E( Vec3 ) + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + i = i + 1 + end + +end + + +--- FormationRightWing Handler OnAfter for AI_FORMATION +-- @function [parent=#AI_FORMATION] OnAfterFormationLeftWing +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XSpace The space on the X-axis in meters between each group. +-- @param #nubmer YSpace The start position on the Y-axis in meters for each group. +-- @param #number ZSpace The start position on the Z-axis in meters for each group. +function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + PointVec3:SetX( i * XSpace ) + PointVec3:SetY( i * YSpace ) + PointVec3:SetZ( -ZSpace ) + + local Vec3 = PointVec3:GetVec3() + self:E( Vec3 ) + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + i = i + 1 + end + +end + --- @param Follow#AI_FORMATION self function AI_FORMATION:onenterFollowing( FollowGroupSet ) @@ -194,111 +469,108 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) end FollowGroupSet:ForEachGroup( - --- @param Group#GROUP FollowGroup - -- @param Unit#UNIT ClientUnit + --- @param Wrapper.Group#GROUP FollowGroup + -- @param Wrapper.Unit#UNIT ClientUnit function( FollowGroup, ClientUnit, CT1, CV1, CT2, CV2 ) local GroupUnit = FollowGroup:GetUnit( 1 ) local FollowFormation = FollowGroup:GetState( self, "Vec3" ) - self:T( FollowFormation ) - local FollowDistance = FollowFormation.x - - self:T( {ClientUnit.UnitName, GroupUnit.UnitName } ) - - local GT1 = GroupUnit:GetState( self, "GT1" ) - - if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then - GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() ) - GroupUnit:SetState( self, "GT1", timer.getTime() ) - else - local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 - local CT = CT2 - CT1 - - local CS = ( 3600 / CT ) * ( CD / 1000 ) - - self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) - + if FollowFormation then + local FollowDistance = FollowFormation.x + local GT1 = GroupUnit:GetState( self, "GT1" ) - local GT2 = timer.getTime() - local GV1 = GroupUnit:GetState( self, "GV1" ) - local GV2 = GroupUnit:GetPointVec3() - GroupUnit:SetState( self, "GT1", GT2 ) - GroupUnit:SetState( self, "GV1", GV2 ) - - local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 - local GT = GT2 - GT1 - - local GS = ( 3600 / GT ) * ( GD / 1000 ) - - self:T2( { "Group:", GS, GD, GT, GV2, GV1, GT2, GT1 } ) - - -- Calculate the group direction vector - local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } - - -- Calculate GH2, GH2 with the same height as CV2. - local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } - - -- Calculate the angle of GV to the orthonormal plane - local alpha = math.atan2( GV.z, GV.x ) - - -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. - -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) - local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), - y = GH2.y + FollowFormation.y, - z = CV2.z + FollowDistance * math.sin(alpha), - } - - -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. - local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } - - -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. - -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. - -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... - local DVu = { x = DV.x / FollowDistance, y = DV.y / FollowDistance, z = DV.z / FollowDistance } - - -- Now we can calculate the group destination vector GDV. - local GDV = { x = DVu.x * CS * 8 + CVI.x, y = CVI.y, z = DVu.z * CS * 8 + CVI.z } - - local GDV_Formation = { - x = GDV.x + ( FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha) ), - y = GDV.y, - z = GDV.z + ( FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha) ) - } - - if self.SmokeDirectionVector == true then - trigger.action.smoke( GDV, trigger.smokeColor.Green ) - trigger.action.smoke( GDV_Formation, trigger.smokeColor.White ) + + if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then + GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() ) + GroupUnit:SetState( self, "GT1", timer.getTime() ) + else + local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 + local CT = CT2 - CT1 + + local CS = ( 3600 / CT ) * ( CD / 1000 ) + + self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + + local GT1 = GroupUnit:GetState( self, "GT1" ) + local GT2 = timer.getTime() + local GV1 = GroupUnit:GetState( self, "GV1" ) + local GV2 = GroupUnit:GetPointVec3() + GroupUnit:SetState( self, "GT1", GT2 ) + GroupUnit:SetState( self, "GV1", GV2 ) + + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 + local GT = GT2 - GT1 + + local GS = ( 3600 / GT ) * ( GD / 1000 ) + + --self:E( { "Group:", GS = GS,GD = GD, GT = GT, GV2 = GV2, GV1 = GV1, GT2 = GT2, GT1 = GT1 } ) + + -- Calculate the group direction vector + local GV = { x = GV2.x - CV2.x + FollowFormation.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z + FollowFormation.z } + + -- Calculate GH2, GH2 with the same height as CV2. + local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } + + -- Calculate the angle of GV to the orthonormal plane + local alpha = math.atan2( GV.z, GV.x ) + + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. + -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) + local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + y = GH2.y, -- + FollowFormation.y, + z = CV2.z + FollowDistance * math.sin(alpha), + } + + -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. + local DV = { x = CV2.x - CVI.x, y = CV2.y - CVI.y, z = CV2.z - CVI.z } + + -- We now calculate the unary direction vector DVu, so that we can multiply DVu with the speed, which is expressed in meters / s. + -- We need to calculate this vector to predict the point the escort group needs to fly to according its speed. + -- The distance of the destination point should be far enough not to have the aircraft starting to swipe left to right... + local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance } + + -- Now we can calculate the group destination vector GDV. + local GDV = { x = DVu.x * CS * 10 + CVI.x, y = CVI.y, z = DVu.z * CS * 10 + CVI.z } + + local ADDx = FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha) + local ADDz = FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha) + + self:E( { ALPHA = alpha, GDVx = GDV.x, GDVz = GDV.z, ADDx = ADDx, ADDz = ADDz, FOLLOWx = FollowFormation.x, FOLLOWz = FollowFormation.z } ) + +-- local GDV_Formation = GDV + local GDV_Formation = { + x = GDV.x + ADDx, + y = GDV.y, + z = GDV.z + ADDz + } + + if self.SmokeDirectionVector == true then + trigger.action.smoke( GDV, trigger.smokeColor.Green ) + trigger.action.smoke( GDV_Formation, trigger.smokeColor.White ) + end + + -- Measure distance between client and group + local CatchUpDistance = ( ( GDV_Formation.x - GV2.x )^2 + ( GDV_Formation.y - GV2.y )^2 + ( GDV_Formation.z - GV2.z )^2 ) ^ 0.5 + + -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome + -- the requested Distance). + local Time = 10 + local CatchUpSpeed = ( CatchUpDistance - ( CS * 20 ) ) / Time + + local Speed = CS + CatchUpSpeed + if Speed < 0 then + Speed = 0 + end + + -- Now route the escort to the desired point with the desired speed. + FollowGroup:RouteToVec3( GDV_Formation, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) end - - self:T3( { "CV2:", CV2 } ) - self:T3( { "CVI:", CVI } ) - self:T2( { "GDV:", GDV } ) - - -- Measure distance between client and group - local CatchUpDistance = ( ( GDV_Formation.x - GV2.x )^2 + ( GDV_Formation.y - GV2.y )^2 + ( GDV_Formation.z - GV2.z )^2 ) ^ 0.5 - - -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome - -- the requested Distance). - local Time = 20 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 9.5 ) ) / Time - - local Speed = CS + CatchUpSpeed - if Speed < 0 then - Speed = 0 - end - - self:T({CatchUpDistance, CatchUpSpeed}) - - self:T3( { "Client Speed, Follow Speed, Speed, FollowDistance, Time:", CS, GS, Speed, FollowDistance, Time } ) - - -- Now route the escort to the desired point with the desired speed. - FollowGroup:RouteToVec3( GDV_Formation, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) end end, ClientUnit, CT1, CV1, CT2, CV2 ) - self:__Follow( -0.5 ) + self:__Follow( -10 ) end end diff --git a/docs/Documentation/AI_Follow.html b/docs/Documentation/AI_Follow.html index 7cd88cbc5..662723ab7 100644 --- a/docs/Documentation/AI_Follow.html +++ b/docs/Documentation/AI_Follow.html @@ -197,12 +197,84 @@ AI_FORMATION.FollowUnit + + + + AI_FORMATION:FormationLeftLine() + +

      FormationLeftLine Trigger for AI_FORMATION

      + + + + AI_FORMATION:FormationLeftWing() + +

      FormationLeftWing Trigger for AI_FORMATION

      + + + + AI_FORMATION:FormationRightLine() + +

      FormationRightLine Trigger for AI_FORMATION

      + + + + AI_FORMATION:FormationRightWing() + +

      FormationRightWing Trigger for AI_FORMATION

      AI_FORMATION:New(FollowUnit, FollowGroupSet, FollowName, FollowBriefing)

      AI_FORMATION class constructor for an AI group

      + + + + AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightLine Handler OnAfter for AI_FORMATION

      + + + + AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightWing Handler OnAfter for AI_FORMATION

      + + + + AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightLine Handler OnAfter for AI_FORMATION

      + + + + AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightWing Handler OnAfter for AI_FORMATION

      + + + + AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationLeftLine Handler OnBefore for AI_FORMATION

      + + + + AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationLeftWing Handler OnBefore for AI_FORMATION

      + + + + AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightLine Handler OnBefore for AI_FORMATION

      + + + + AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +

      FormationRightWing Handler OnBefore for AI_FORMATION

      @@ -227,6 +299,54 @@ AI_FORMATION:TestSmokeDirectionVector(SmokeDirection)

      This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.

      + + + + AI_FORMATION:__FormationLeftLine(Delay) + +

      FormationLeftLine Asynchronous Trigger for AI_FORMATION

      + + + + AI_FORMATION:__FormationLeftWing(Delay) + +

      FormationLeftWing Asynchronous Trigger for AI_FORMATION

      + + + + AI_FORMATION:__FormationRightLine(Delay) + +

      FormationRightLine Asynchronous Trigger for AI_FORMATION

      + + + + AI_FORMATION:__FormationRightWing(Delay) + +

      FormationRightWing Asynchronous Trigger for AI_FORMATION

      + + + + AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + + + + + + AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + + + + + + AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + + + + + + AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + + @@ -311,10 +431,18 @@

      The following menus are created within the RADIO MENU of an active unit hosted by a player:

      +

      Usage:

      -- Declare a new FollowPlanes object as follows:
       
      @@ -431,6 +559,58 @@ FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to
       	
       
       
      +
      +
    +
    +
    + + +AI_FORMATION:FormationLeftLine() + +
    +
    + +

    FormationLeftLine Trigger for AI_FORMATION

    + +
    +
    +
    +
    + + +AI_FORMATION:FormationLeftWing() + +
    +
    + +

    FormationLeftWing Trigger for AI_FORMATION

    + +
    +
    +
    +
    + + +AI_FORMATION:FormationRightLine() + +
    +
    + +

    FormationRightLine Trigger for AI_FORMATION

    + +
    +
    +
    +
    + + +AI_FORMATION:FormationRightWing() + +
    +
    + +

    FormationRightWing Trigger for AI_FORMATION

    +
    @@ -454,7 +634,7 @@ The UNIT leading the FolllowGroupSet.

  • -

    Set#SET_GROUP FollowGroupSet : +

    Core.Set#SET_GROUP FollowGroupSet : The group AI escorting the FollowUnit.

  • @@ -475,6 +655,466 @@ Name of the escort.

    #AI_FORMATION: self

    + +
    +
    +
    + + +AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightLine Handler OnAfter for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightWing Handler OnAfter for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightLine Handler OnAfter for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightWing Handler OnAfter for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationLeftLine Handler OnBefore for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationLeftWing Handler OnBefore for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightLine Handler OnBefore for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +

    Return value

    + +

    #boolean:

    + + +
    +
    +
    +
    + + +AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + +

    FormationRightWing Handler OnBefore for AI_FORMATION

    + +

    Parameters

    +
      +
    • + +

      Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      + +
    • +
    • + +

      #string From :

      + +
    • +
    • + +

      #string Event :

      + +
    • +
    • + +

      #string To :

      + +
    • +
    • + +

      #number XSpace : +The space on the X-axis in meters between each group.

      + +
    • +
    • + +

      #nubmer YSpace : +The start position on the Y-axis in meters for each group.

      + +
    • +
    • + +

      #number ZSpace : +The start position on the Z-axis in meters for each group.

      + +
    • +
    +

    Return value

    + +

    #boolean:

    + +
    @@ -546,6 +1186,294 @@ If true, then the direction vector will be smoked.

    + +AI_FORMATION:__FormationLeftLine(Delay) + +
    +
    + +

    FormationLeftLine Asynchronous Trigger for AI_FORMATION

    + +

    Parameter

    +
      +
    • + +

      #number Delay :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:__FormationLeftWing(Delay) + +
    +
    + +

    FormationLeftWing Asynchronous Trigger for AI_FORMATION

    + +

    Parameter

    +
      +
    • + +

      #number Delay :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:__FormationRightLine(Delay) + +
    +
    + +

    FormationRightLine Asynchronous Trigger for AI_FORMATION

    + +

    Parameter

    +
      +
    • + +

      #number Delay :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:__FormationRightWing(Delay) + +
    +
    + +

    FormationRightWing Asynchronous Trigger for AI_FORMATION

    + +

    Parameter

    +
      +
    • + +

      #number Delay :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + + + +

    Parameters

    +
      +
    • + +

      FollowGroupSet :

      + +
    • +
    • + +

      From :

      + +
    • +
    • + +

      Event :

      + +
    • +
    • + +

      To :

      + +
    • +
    • + +

      XSpace :

      + +
    • +
    • + +

      YSpace :

      + +
    • +
    • + +

      ZSpace :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + + + +

    Parameters

    +
      +
    • + +

      FollowGroupSet :

      + +
    • +
    • + +

      From :

      + +
    • +
    • + +

      Event :

      + +
    • +
    • + +

      To :

      + +
    • +
    • + +

      XSpace :

      + +
    • +
    • + +

      YSpace :

      + +
    • +
    • + +

      ZSpace :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + + + +

    Parameters

    +
      +
    • + +

      FollowGroupSet :

      + +
    • +
    • + +

      From :

      + +
    • +
    • + +

      Event :

      + +
    • +
    • + +

      To :

      + +
    • +
    • + +

      XSpace :

      + +
    • +
    • + +

      YSpace :

      + +
    • +
    • + +

      ZSpace :

      + +
    • +
    +
    +
    +
    +
    + + +AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + +
    +
    + + + +

    Parameters

    +
      +
    • + +

      FollowGroupSet :

      + +
    • +
    • + +

      From :

      + +
    • +
    • + +

      Event :

      + +
    • +
    • + +

      To :

      + +
    • +
    • + +

      XSpace :

      + +
    • +
    • + +

      YSpace :

      + +
    • +
    • + +

      ZSpace :

      + +
    • +
    +
    +
    +
    +
    + AI_FORMATION:onenterFollowing(FollowGroupSet) @@ -663,6 +1591,8 @@ If true, then the direction vector will be smoked.

    +

    Type nubmer

    + diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index bebc26831..4b91533d8 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -953,6 +953,9 @@ Use the method AIPATROLZONE.M + +

    This table contains the targets detected during patrol.

    +
    diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 8fadae3b5..0cf77d270 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -3046,7 +3046,6 @@ The range till cargo will board.

    - #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 62e57668f..c21d35a8d 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2337,7 +2337,6 @@ The index of the DetectedItem.

    - #number DETECTION_BASE.DetectedItemMax diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index f0ab48a01..2807d80e3 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -1624,7 +1624,7 @@ A string defining the start state.

    - #string + FSM._StartState @@ -1923,6 +1923,7 @@ A string defining the start state.

    + FSM.current diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index c732cbe69..eb07aae68 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -215,6 +215,7 @@ on defined intervals (currently every minute).

    + #number MOVEMENT.AliveUnits @@ -223,6 +224,9 @@ on defined intervals (currently every minute).

    + +

    Contains the counter how many units are currently alive

    +
    diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 4a10c8567..0d752635f 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -772,6 +772,12 @@ and any spaces before and after the resulting name are removed.

    SPAWN:_TranslateRotate(SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle) + + + + SPAWN.uncontrolled + + @@ -2529,9 +2535,6 @@ when nothing was spawned.

    - -

    Overwrite unit names by default with group name.

    -
    @@ -2546,9 +2549,6 @@ when nothing was spawned.

    - -

    By default, no InitLimit

    -
    @@ -2584,7 +2584,7 @@ when nothing was spawned.

    - #number + SPAWN.SpawnMaxGroups @@ -2601,7 +2601,7 @@ when nothing was spawned.

    - #number + SPAWN.SpawnMaxUnitsAlive @@ -2929,7 +2929,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
    - + #boolean SPAWN.SpawnUnControlled @@ -3519,6 +3519,20 @@ True = Continue Scheduler

    + +
    +
    +
    + + + +SPAWN.uncontrolled + +
    +
    + + +
    diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index 69a9412e9..8750f8d57 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -446,7 +446,6 @@ ptional) The name of the new static.

    - #number SPAWNSTATIC.SpawnIndex diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 5c03c9d31..64abe7762 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -503,7 +503,7 @@ based on the tasking capabilities defined in Task#TA
    - + Core.Cargo#CARGO_GROUP FSM_PROCESS.Cargo From 2c4a33aacb6993a088b85379a3e6f113d72dc57b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 12:38:24 +0200 Subject: [PATCH 22/32] Fixes --- Moose Development/Moose/AI/AI_Formation.lua | 176 +++++++++++++------- 1 file changed, 115 insertions(+), 61 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index d3a18880a..7c31c16f3 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -143,9 +143,10 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #boolean --- FormationLeftLine Handler OnAfter for AI_FORMATION @@ -155,18 +156,27 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationLeftLine Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] FormationLeftLine -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationLeftLine Asynchronous Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] __FormationLeftLine -- @param #AI_FORMATION self -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. self:AddTransition( "*", "FormationRightLine", "*" ) @@ -178,9 +188,10 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #boolean --- FormationRightLine Handler OnAfter for AI_FORMATION @@ -190,18 +201,27 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationRightLine Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] FormationRightLine -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationRightLine Asynchronous Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] __FormationRightLine -- @param #AI_FORMATION self -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. self:AddTransition( "*", "FormationLeftWing", "*" ) @@ -212,9 +232,11 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #boolean --- FormationLeftWing Handler OnAfter for AI_FORMATION @@ -224,18 +246,30 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationLeftWing Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] FormationLeftWing -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationLeftWing Asynchronous Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] __FormationLeftWing -- @param #AI_FORMATION self -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. self:AddTransition( "*", "FormationRightWing", "*" ) @@ -247,9 +281,11 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #boolean --- FormationRightWing Handler OnAfter for AI_FORMATION @@ -259,26 +295,35 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #string From -- @param #string Event -- @param #string To - -- @param #number XSpace The space on the X-axis in meters between each group. - -- @param #nubmer YSpace The start position on the Y-axis in meters for each group. - -- @param #number ZSpace The start position on the Z-axis in meters for each group. + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationRightWing Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] FormationRightWing -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. --- FormationRightWing Asynchronous Trigger for AI_FORMATION -- @function [parent=#AI_FORMATION] __FormationRightWing -- @param #AI_FORMATION self -- @param #number Delay - - - + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. self:AddTransition( "*", "Follow", "Following" ) - self:FormationLeftLine( 50, 0, 100 ) + self:FormationLeftLine( 500, 0, 250, 250 ) self.FollowName = FollowName self.FollowBriefing = FollowBriefing @@ -309,11 +354,12 @@ end -- @param #string From -- @param #string Event -- @param #string To --- @param #number XSpace The space on the X-axis in meters between each group. --- @param #nubmer YSpace The start position on the Y-axis in meters for each group. --- @param #number ZSpace The start position on the Z-axis in meters for each group. -function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) - self:E( { FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace } ) +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) + self:E( { FollowGroupSet, From , Event ,To, XStart, YStart, ZStart, ZSpace } ) FollowGroupSet:Flush() @@ -324,9 +370,9 @@ function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , T for FollowID, FollowGroup in pairs( FollowSet ) do local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( -XSpace ) - PointVec3:SetY( YSpace ) - PointVec3:SetZ( i * ZSpace ) + PointVec3:SetX( XStart ) + PointVec3:SetY( YStart ) + PointVec3:SetZ( ZStart + i * ZSpace ) local Vec3 = PointVec3:GetVec3() self:E( Vec3 ) @@ -340,16 +386,18 @@ end --- FormationRightLine Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationLeftLine +-- @function [parent=#AI_FORMATION] OnAfterFormationRightLine -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From -- @param #string Event -- @param #string To --- @param #number XSpace The space on the X-axis in meters between each group. --- @param #nubmer YSpace The start position on the Y-axis in meters for each group. --- @param #number ZSpace The start position on the Z-axis in meters for each group. -function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) + self:E( { FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace } ) local FollowSet = FollowGroupSet:GetSet() @@ -358,9 +406,9 @@ function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , for FollowID, FollowGroup in pairs( FollowSet ) do local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( i * XSpace ) - PointVec3:SetY( YSpace ) - PointVec3:SetZ( -ZSpace ) + PointVec3:SetX( XStart ) + PointVec3:SetY( YStart ) + PointVec3:SetZ( -(ZStart + i * ZSpace) ) local Vec3 = PointVec3:GetVec3() self:E( Vec3 ) @@ -380,10 +428,12 @@ end -- @param #string From -- @param #string Event -- @param #string To --- @param #number XSpace The space on the X-axis in meters between each group. --- @param #nubmer YSpace The start position on the Y-axis in meters for each group. --- @param #number ZSpace The start position on the Z-axis in meters for each group. -function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) local FollowSet = FollowGroupSet:GetSet() @@ -392,9 +442,9 @@ function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , T for FollowID, FollowGroup in pairs( FollowSet ) do local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( -i * XSpace ) - PointVec3:SetY( i * YSpace ) - PointVec3:SetZ( -ZSpace ) + PointVec3:SetX( XStart + i * XSpace ) + PointVec3:SetY( YStart ) + PointVec3:SetZ( ZStart + i * ZSpace ) local Vec3 = PointVec3:GetVec3() self:E( Vec3 ) @@ -408,16 +458,18 @@ end --- FormationRightWing Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationLeftWing +-- @function [parent=#AI_FORMATION] OnAfterFormationRightWing -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From -- @param #string Event -- @param #string To --- @param #number XSpace The space on the X-axis in meters between each group. --- @param #nubmer YSpace The start position on the Y-axis in meters for each group. --- @param #number ZSpace The start position on the Z-axis in meters for each group. -function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XSpace, YSpace, ZSpace ) +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) local FollowSet = FollowGroupSet:GetSet() @@ -426,10 +478,10 @@ function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , for FollowID, FollowGroup in pairs( FollowSet ) do local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( i * XSpace ) - PointVec3:SetY( i * YSpace ) - PointVec3:SetZ( -ZSpace ) - + PointVec3:SetX( XStart + i * XSpace ) + PointVec3:SetY( YStart ) + PointVec3:SetZ( -(ZStart + i * ZSpace) ) + local Vec3 = PointVec3:GetVec3() self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) @@ -441,6 +493,8 @@ function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , end + + --- @param Follow#AI_FORMATION self function AI_FORMATION:onenterFollowing( FollowGroupSet ) self:F( ) @@ -555,7 +609,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome -- the requested Distance). local Time = 10 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 20 ) ) / Time + local CatchUpSpeed = ( CatchUpDistance - ( CS * 15 ) ) / Time local Speed = CS + CatchUpSpeed if Speed < 0 then From 80a88058c09a7a1f5ad44189fe8e6cede1bd3ee5 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 12:45:01 +0200 Subject: [PATCH 23/32] Documentation --- docs/Documentation/AI_Follow.html | 539 +++++++++++++++++++++++------ docs/Documentation/Cargo.html | 1 + docs/Documentation/Database.html | 1 - docs/Documentation/Designate.html | 1 + docs/Documentation/Detection.html | 2 +- docs/Documentation/Spawn.html | 23 +- docs/Documentation/Task_Cargo.html | 2 +- 7 files changed, 444 insertions(+), 125 deletions(-) diff --git a/docs/Documentation/AI_Follow.html b/docs/Documentation/AI_Follow.html index 662723ab7..a09fbf172 100644 --- a/docs/Documentation/AI_Follow.html +++ b/docs/Documentation/AI_Follow.html @@ -200,25 +200,25 @@ - AI_FORMATION:FormationLeftLine() + AI_FORMATION:FormationLeftLine(XStart, YStart, ZStart, ZSpace)

    FormationLeftLine Trigger for AI_FORMATION

    - AI_FORMATION:FormationLeftWing() + AI_FORMATION:FormationLeftWing(XStart, XSpace, YStart, ZStart, ZSpace)

    FormationLeftWing Trigger for AI_FORMATION

    - AI_FORMATION:FormationRightLine() + AI_FORMATION:FormationRightLine(XStart, YStart, ZStart, ZSpace)

    FormationRightLine Trigger for AI_FORMATION

    - AI_FORMATION:FormationRightWing() + AI_FORMATION:FormationRightWing(XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Trigger for AI_FORMATION

    @@ -230,49 +230,49 @@ - AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) + +

    FormationLeftLine Handler OnAfter for AI_FORMATION

    + + + + AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) + +

    FormationLeftWing Handler OnAfter for AI_FORMATION

    + + + + AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)

    FormationRightLine Handler OnAfter for AI_FORMATION

    - AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Handler OnAfter for AI_FORMATION

    - AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) - -

    FormationRightLine Handler OnAfter for AI_FORMATION

    - - - - AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) - -

    FormationRightWing Handler OnAfter for AI_FORMATION

    - - - - AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)

    FormationLeftLine Handler OnBefore for AI_FORMATION

    - AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationLeftWing Handler OnBefore for AI_FORMATION

    - AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)

    FormationRightLine Handler OnBefore for AI_FORMATION

    - AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Handler OnBefore for AI_FORMATION

    @@ -302,49 +302,49 @@ - AI_FORMATION:__FormationLeftLine(Delay) + AI_FORMATION:__FormationLeftLine(Delay, XStart, YStart, ZStart, ZSpace)

    FormationLeftLine Asynchronous Trigger for AI_FORMATION

    - AI_FORMATION:__FormationLeftWing(Delay) + AI_FORMATION:__FormationLeftWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationLeftWing Asynchronous Trigger for AI_FORMATION

    - AI_FORMATION:__FormationRightLine(Delay) + AI_FORMATION:__FormationRightLine(Delay, XStart, YStart, ZStart, ZSpace)

    FormationRightLine Asynchronous Trigger for AI_FORMATION

    - AI_FORMATION:__FormationRightWing(Delay) + AI_FORMATION:__FormationRightWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Asynchronous Trigger for AI_FORMATION

    - AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) - AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) - AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) - AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) + AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) @@ -565,52 +565,172 @@ FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to
    -AI_FORMATION:FormationLeftLine() +AI_FORMATION:FormationLeftLine(XStart, YStart, ZStart, ZSpace)

    FormationLeftLine Trigger for AI_FORMATION

    +

    Parameters

    +
      +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      + +
    • +
    -AI_FORMATION:FormationLeftWing() +AI_FORMATION:FormationLeftWing(XStart, XSpace, YStart, ZStart, ZSpace)

    FormationLeftWing Trigger for AI_FORMATION

    +

    Parameters

    +
      +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      + +
    • +
    -AI_FORMATION:FormationRightLine() +AI_FORMATION:FormationRightLine(XStart, YStart, ZStart, ZSpace)

    FormationRightLine Trigger for AI_FORMATION

    +

    Parameters

    +
      +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      + +
    • +
    -AI_FORMATION:FormationRightWing() +AI_FORMATION:FormationRightWing(XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Trigger for AI_FORMATION

    +

    Parameters

    +
      +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      + +
    • +
    @@ -661,12 +781,12 @@ self

    -AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    -

    FormationRightLine Handler OnAfter for AI_FORMATION

    +

    FormationLeftLine Handler OnAfter for AI_FORMATION

    Parameters

      @@ -693,20 +813,26 @@ The group AI escorting the FollowUnit.

    • -

      #number XSpace : -The space on the X-axis in meters between each group.

      +

      #number XStart : +The start position on the X-axis in meters for the first group.

    • -

      #nubmer YSpace : -The start position on the Y-axis in meters for each group.

      +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

    • #number ZSpace : -The start position on the Z-axis in meters for each group.

      +The space between groups on the Z-axis in meters for each sequent group.

    @@ -716,12 +842,12 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    -

    FormationRightWing Handler OnAfter for AI_FORMATION

    +

    FormationLeftWing Handler OnAfter for AI_FORMATION

    Parameters

      @@ -748,20 +874,32 @@ The group AI escorting the FollowUnit.

    • -

      #number XSpace : -The space on the X-axis in meters between each group.

      +

      #number XStart : +The start position on the X-axis in meters for the first group.

    • -

      #nubmer YSpace : -The start position on the Y-axis in meters for each group.

      +

      #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

    • #number ZSpace : -The start position on the Z-axis in meters for each group.

      +The space between groups on the Z-axis in meters for each sequent group.

    @@ -771,7 +909,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    @@ -803,20 +941,26 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -826,7 +970,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    @@ -858,20 +1002,32 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

    + +
  • +
  • + +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -881,7 +1037,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    @@ -913,20 +1069,26 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -941,7 +1103,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    @@ -973,20 +1135,32 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

    + +
  • +
  • + +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -1001,7 +1175,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnBeforeFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    @@ -1033,20 +1207,26 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -1061,7 +1241,7 @@ The start position on the Z-axis in meters for each group.

    -AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    @@ -1093,20 +1273,32 @@ The group AI escorting the FollowUnit.

  • -

    #number XSpace : -The space on the X-axis in meters between each group.

    +

    #number XStart : +The start position on the X-axis in meters for the first group.

  • -

    #nubmer YSpace : -The start position on the Y-axis in meters for each group.

    +

    #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

    + +
  • +
  • + +

    #nubmer YStart : +The start position on the Y-axis in meters for the first group.

    + +
  • +
  • + +

    #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

  • #number ZSpace : -The start position on the Z-axis in meters for each group.

    +The space between groups on the Z-axis in meters for each sequent group.

  • @@ -1181,25 +1373,54 @@ If true, then the direction vector will be smoked.

    +

    Return value

    + +

    #AI_FORMATION:

    + +
    -AI_FORMATION:__FormationLeftLine(Delay) +AI_FORMATION:__FormationLeftLine(Delay, XStart, YStart, ZStart, ZSpace)

    FormationLeftLine Asynchronous Trigger for AI_FORMATION

    -

    Parameter

    +

    Parameters

    • #number Delay :

      +
    • +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +
    @@ -1208,19 +1429,49 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:__FormationLeftWing(Delay) +AI_FORMATION:__FormationLeftWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationLeftWing Asynchronous Trigger for AI_FORMATION

    -

    Parameter

    +

    Parameters

    • #number Delay :

      +
    • +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +
    @@ -1229,19 +1480,43 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:__FormationRightLine(Delay) +AI_FORMATION:__FormationRightLine(Delay, XStart, YStart, ZStart, ZSpace)

    FormationRightLine Asynchronous Trigger for AI_FORMATION

    -

    Parameter

    +

    Parameters

    • #number Delay :

      +
    • +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +
    @@ -1250,19 +1525,49 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:__FormationRightWing(Delay) +AI_FORMATION:__FormationRightWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

    FormationRightWing Asynchronous Trigger for AI_FORMATION

    -

    Parameter

    +

    Parameters

    • #number Delay :

      +
    • +
    • + +

      #number XStart : +The start position on the X-axis in meters for the first group.

      + +
    • +
    • + +

      #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      + +
    • +
    • + +

      #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      + +
    • +
    • + +

      #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      + +
    • +
    • + +

      #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +
    @@ -1271,7 +1576,7 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    @@ -1302,12 +1607,17 @@ If true, then the direction vector will be smoked.

  • -

    XSpace :

    +

    XStart :

  • -

    YSpace :

    +

    YStart :

    + +
  • +
  • + +

    ZStart :

  • @@ -1322,7 +1632,7 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    @@ -1353,12 +1663,22 @@ If true, then the direction vector will be smoked.

  • +

    XStart :

    + +
  • +
  • +

    XSpace :

  • -

    YSpace :

    +

    YStart :

    + +
  • +
  • + +

    ZStart :

  • @@ -1373,7 +1693,7 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
    @@ -1404,12 +1724,17 @@ If true, then the direction vector will be smoked.

  • -

    XSpace :

    +

    XStart :

  • -

    YSpace :

    +

    YStart :

    + +
  • +
  • + +

    ZStart :

  • @@ -1424,7 +1749,7 @@ If true, then the direction vector will be smoked.

    -AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XSpace, YSpace, ZSpace) +AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)
    @@ -1455,12 +1780,22 @@ If true, then the direction vector will be smoked.

  • +

    XStart :

    + +
  • +
  • +

    XSpace :

  • -

    YSpace :

    +

    YStart :

    + +
  • +
  • + +

    ZStart :

  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 0cf77d270..8fadae3b5 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -3046,6 +3046,7 @@ The range till cargo will board.

    + #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index 08030f60c..f42768741 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -1830,7 +1830,6 @@ self

    - #number DATABASE.UNITS_Position diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index cf1f82b99..3a8e05379 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -892,6 +892,7 @@ function below will use the range 1-7 just in case

    + DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index c21d35a8d..aca76ca67 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2476,7 +2476,7 @@ The index of the DetectedItem.

    - #number + DETECTION_BASE.DetectionInterval diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 0d752635f..f062c47c4 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -772,12 +772,6 @@ and any spaces before and after the resulting name are removed.

    SPAWN:_TranslateRotate(SpawnIndex, SpawnRootX, SpawnRootY, SpawnX, SpawnY, SpawnAngle) - - - - SPAWN.uncontrolled - - @@ -2535,6 +2529,9 @@ when nothing was spawned.

    + +

    Overwrite unit names by default with group name.

    +
  • @@ -3519,20 +3516,6 @@ True = Continue Scheduler

    - -
    -
    -
    - - - -SPAWN.uncontrolled - -
    -
    - - -
    diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 64abe7762..5c03c9d31 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -503,7 +503,7 @@ based on the tasking capabilities defined in Task#TA
    - Core.Cargo#CARGO_GROUP + FSM_PROCESS.Cargo From 15c52e03d94b214d6fe3eeeace131ba3353a1047 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 12:48:10 +0200 Subject: [PATCH 24/32] Documentation updates --- Moose Development/Moose/AI/AI_BAI.lua | 2 +- Moose Development/Moose/AI/AI_Formation.lua | 2 +- docs/Documentation/AI_BAI.html | 8 +- docs/Documentation/AI_Balancer.html | 4 +- docs/Documentation/AI_Cap.html | 4 +- docs/Documentation/AI_Cas.html | 4 +- docs/Documentation/AI_Formation.html | 1935 +++++++++++++++++++ docs/Documentation/AI_Patrol.html | 7 +- docs/Documentation/Account.html | 4 +- docs/Documentation/Airbase.html | 4 +- docs/Documentation/AirbasePolice.html | 4 +- docs/Documentation/Assign.html | 4 +- docs/Documentation/Base.html | 4 +- docs/Documentation/Cargo.html | 4 +- docs/Documentation/CleanUp.html | 4 +- docs/Documentation/Client.html | 4 +- docs/Documentation/CommandCenter.html | 4 +- docs/Documentation/Controllable.html | 4 +- docs/Documentation/DCSAirbase.html | 4 +- docs/Documentation/DCSCoalitionObject.html | 4 +- docs/Documentation/DCSCommand.html | 4 +- docs/Documentation/DCSController.html | 4 +- docs/Documentation/DCSGroup.html | 4 +- docs/Documentation/DCSObject.html | 4 +- docs/Documentation/DCSTask.html | 4 +- docs/Documentation/DCSTypes.html | 4 +- docs/Documentation/DCSUnit.html | 4 +- docs/Documentation/DCSVec3.html | 4 +- docs/Documentation/DCSWorld.html | 4 +- docs/Documentation/DCSZone.html | 4 +- docs/Documentation/DCScountry.html | 4 +- docs/Documentation/DCStimer.html | 4 +- docs/Documentation/DCStrigger.html | 4 +- docs/Documentation/Database.html | 5 +- docs/Documentation/Designate.html | 5 +- docs/Documentation/Detection.html | 6 +- docs/Documentation/DetectionManager.html | 4 +- docs/Documentation/Escort.html | 4 +- docs/Documentation/Event.html | 4 +- docs/Documentation/Fsm.html | 7 +- docs/Documentation/Group.html | 4 +- docs/Documentation/Identifiable.html | 4 +- docs/Documentation/Menu.html | 4 +- docs/Documentation/Message.html | 4 +- docs/Documentation/MissileTrainer.html | 4 +- docs/Documentation/Mission.html | 4 +- docs/Documentation/Movement.html | 8 +- docs/Documentation/Object.html | 4 +- docs/Documentation/Point.html | 4 +- docs/Documentation/Positionable.html | 4 +- docs/Documentation/Process_JTAC.html | 4 +- docs/Documentation/Process_Pickup.html | 4 +- docs/Documentation/Radio.html | 4 +- docs/Documentation/Route.html | 4 +- docs/Documentation/Scenery.html | 4 +- docs/Documentation/ScheduleDispatcher.html | 4 +- docs/Documentation/Scheduler.html | 4 +- docs/Documentation/Scoring.html | 4 +- docs/Documentation/Sead.html | 4 +- docs/Documentation/Set.html | 4 +- docs/Documentation/Smoke.html | 4 +- docs/Documentation/Spawn.html | 34 +- docs/Documentation/SpawnStatic.html | 5 +- docs/Documentation/Spot.html | 8 +- docs/Documentation/Static.html | 4 +- docs/Documentation/StaticObject.html | 4 +- docs/Documentation/Task.html | 4 +- docs/Documentation/Task_A2G.html | 4 +- docs/Documentation/Task_A2G_Dispatcher.html | 4 +- docs/Documentation/Task_Cargo.html | 7 +- docs/Documentation/Task_PICKUP.html | 4 +- docs/Documentation/Unit.html | 4 +- docs/Documentation/Utils.html | 4 +- docs/Documentation/Zone.html | 4 +- docs/Documentation/env.html | 4 +- docs/Documentation/index.html | 8 +- docs/Documentation/land.html | 4 +- docs/Documentation/routines.html | 4 +- 78 files changed, 2105 insertions(+), 194 deletions(-) create mode 100644 docs/Documentation/AI_Formation.html diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index cd3a028be..efa68c3b1 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -51,7 +51,7 @@ -- -- * **FlightControl**: Concept, Design & Programming. -- --- @module AI_BAI +-- @module AI_Bai --- AI_BAI_ZONE class diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 7c31c16f3..100e9ca35 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -36,7 +36,7 @@ -- -- * **FlightControl**: Concept, Design & Programming. -- --- @module AI_Follow +-- @module AI_Formation --- AI_FORMATION class -- @type AI_FORMATION diff --git a/docs/Documentation/AI_BAI.html b/docs/Documentation/AI_BAI.html index fcf7e478e..a778055c0 100644 --- a/docs/Documentation/AI_BAI.html +++ b/docs/Documentation/AI_BAI.html @@ -17,11 +17,11 @@ index
    -

    Module AI_BAI

    +

    Module AI_Bai

    AI -- Provide Battlefield Air Interdiction (bombing).

    @@ -598,7 +598,7 @@ is the point where a map object is to be destroyed (like a bridge).

    -

    Type AI_BAI

    +

    Type AI_Bai

    Type AI_BAI_ZONE

    diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 412cda7ff..c33e7f6ec 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -17,11 +17,11 @@ index
    diff --git a/docs/Documentation/Account.html b/docs/Documentation/Account.html index c9525a456..5609f0458 100644 --- a/docs/Documentation/Account.html +++ b/docs/Documentation/Account.html @@ -17,11 +17,11 @@ index
      -
    • AI_BAI
    • +
    • AI_Bai
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • -
    • AI_Follow
    • +
    • AI_Formation
    • AI_Patrol
    • Account
    • Airbase
    • @@ -215,7 +215,6 @@ on defined intervals (currently every minute).

      - #number MOVEMENT.AliveUnits @@ -224,9 +223,6 @@ on defined intervals (currently every minute).

      - -

      Contains the counter how many units are currently alive

      -
      diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index 04267f399..1b5902a84 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -17,11 +17,11 @@ index
    @@ -2549,6 +2546,9 @@ when nothing was spawned.

    + +

    By default, no InitLimit

    +
    @@ -2584,7 +2584,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxGroups @@ -2601,7 +2601,7 @@ when nothing was spawned.

    - + #number SPAWN.SpawnMaxUnitsAlive @@ -3519,20 +3519,6 @@ True = Continue Scheduler

    - -
    -
    -
    - - - -SPAWN.uncontrolled - -
    -
    - - -
    diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index 8750f8d57..50d544bd6 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -17,11 +17,11 @@ index
      -
    • AI_BAI
    • +
    • AI_Bai
    • AI_Balancer
    • AI_Cap
    • AI_Cas
    • -
    • AI_Follow
    • +
    • AI_Formation
    • AI_Patrol
    • Account
    • Airbase
    • @@ -98,7 +98,7 @@

      Module

      - + - + diff --git a/docs/Documentation/land.html b/docs/Documentation/land.html index 64ee55186..e3b4d5dc9 100644 --- a/docs/Documentation/land.html +++ b/docs/Documentation/land.html @@ -17,11 +17,11 @@ index
        -
      • AI_BAI
      • +
      • AI_Bai
      • AI_Balancer
      • AI_Cap
      • AI_Cas
      • -
      • AI_Follow
      • +
      • AI_Formation
      • AI_Patrol
      • Account
      • Airbase
      • From 98fb15dfb7937ee854e879dbb38eb03e95fd46b0 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 12:50:19 +0200 Subject: [PATCH 25/32] Documentation --- docs/Documentation/Database.html | 1 + docs/Documentation/Detection.html | 4 +++- docs/Documentation/Fsm.html | 3 ++- docs/Documentation/Movement.html | 4 ++++ docs/Documentation/Spot.html | 4 ++++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index 1953c3339..36577a336 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -1830,6 +1830,7 @@ self

        + #number DATABASE.UNITS_Position diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index b60e01592..491edc91b 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2324,6 +2324,7 @@ The index of the DetectedItem.

        + #number DETECTION_BASE.DetectedItemCount @@ -2337,6 +2338,7 @@ The index of the DetectedItem.

        + #number DETECTION_BASE.DetectedItemMax @@ -2476,7 +2478,7 @@ The index of the DetectedItem.

        - + #number DETECTION_BASE.DetectionInterval diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index c8c189c3e..9f6365bca 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -1624,7 +1624,7 @@ A string defining the start state.

        - #string + FSM._StartState @@ -1923,6 +1923,7 @@ A string defining the start state.

        + FSM.current diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index 45c002a4d..ab459b6d5 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -215,6 +215,7 @@ on defined intervals (currently every minute).

        + #number MOVEMENT.AliveUnits @@ -223,6 +224,9 @@ on defined intervals (currently every minute).

        + +

        Contains the counter how many units are currently alive

        +
        diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index 5befab5b3..3ba35dc6d 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -763,6 +763,7 @@ true if it is lasing

        + SPOT.ScheduleID @@ -776,6 +777,7 @@ true if it is lasing

        + SPOT.SpotIR @@ -789,6 +791,7 @@ true if it is lasing

        + SPOT.SpotLaser @@ -802,6 +805,7 @@ true if it is lasing

        + SPOT.Target From 546b960951a3cd777dafc6d82369789d3aef1167 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 14:10:49 +0200 Subject: [PATCH 26/32] method AI_FORMATION:FormationCenterWing implemented. --- Moose Development/Moose/AI/AI_Formation.lua | 106 +++++- docs/Documentation/AI_Formation.html | 342 +++++++++++++++++++- docs/Documentation/Database.html | 1 - docs/Documentation/Detection.html | 2 +- docs/Documentation/Fsm.html | 3 +- docs/Documentation/Movement.html | 4 - docs/Documentation/Spawn.html | 17 +- docs/Documentation/Task_Cargo.html | 2 +- 8 files changed, 437 insertions(+), 40 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 100e9ca35..6dd2c55df 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -73,19 +73,16 @@ -- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation. -- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation. -- * @{AI_Formation#AI_FORMATION.FormationCenterLine}(): Form a center line formation. --- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation. -- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation. -- -- -- @usage --- -- Declare a new FollowPlanes object as follows: --- --- -- First find the GROUP object and the CLIENT object. --- local FollowUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. --- local FollowGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Follow Client. --- --- -- Now use these 2 objects to construct the new FollowPlanes object. --- FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) +-- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart() +-- FollowGroupSet:Flush() +-- local LeaderUnit = UNIT:FindByName( "Leader" ) +-- local LargeFormation = AI_FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" ) +-- LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 ) +-- LargeFormation:__Start( 1 ) -- -- @field #AI_FORMATION AI_FORMATION = { @@ -320,6 +317,56 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + self:AddTransition( "*", "FormationCenterWing", "*" ) + + --- FormationCenterWing Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationCenterWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @return #boolean + + --- FormationCenterWing Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationCenterWing + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationCenterWing Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationCenterWing + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationCenterWing Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationCenterWing + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + + self:AddTransition( "*", "Follow", "Following" ) @@ -493,6 +540,47 @@ function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , end +--- FormationCenterWing Handler OnAfter for AI_FORMATION +-- @function [parent=#AI_FORMATION] OnAfterFormationCenterWing +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + + local Side = ( i % 2 == 0 ) and 1 or -1 + local Row = i / 2 + 1 + + self:E(Side) + + PointVec3:SetX( XStart + Row * XSpace ) + PointVec3:SetY( YStart ) + PointVec3:SetZ( Side * ( ZStart + i * ZSpace ) ) + + local Vec3 = PointVec3:GetVec3() + self:E( Vec3 ) + FollowGroup:SetState( self, "Vec3", Vec3 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + i = i + 1 + end + +end + --- @param Follow#AI_FORMATION self diff --git a/docs/Documentation/AI_Formation.html b/docs/Documentation/AI_Formation.html index 29d15b7eb..289db76de 100644 --- a/docs/Documentation/AI_Formation.html +++ b/docs/Documentation/AI_Formation.html @@ -197,6 +197,12 @@
      + + + + @@ -227,6 +233,12 @@ + + + + @@ -251,6 +263,12 @@ + + + + @@ -299,6 +317,12 @@ + + + + @@ -323,6 +347,12 @@ + + + + @@ -437,21 +467,18 @@
    • AIFormation#AIFORMATION.FormationRightWing(): Form a right wing formation.
    • AIFormation#AIFORMATION.FormationLeftWing(): Form a left wing formation.
    • AIFormation#AIFORMATION.FormationCenterLine(): Form a center line formation.
    • -
    • AIFormation#AIFORMATION.FormationCenterWing(): Form a center wing formation.
    • AIFormation#AIFORMATION.FormationCenterBoxed(): Form a center boxed formation.
    • Usage:

      -
      -- Declare a new FollowPlanes object as follows:
      -
      --- First find the GROUP object and the CLIENT object.
      -local FollowUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
      -local FollowGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Follow Client.
      -
      --- Now use these 2 objects to construct the new FollowPlanes object.
      -FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
      +		
      local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart()
      +FollowGroupSet:Flush()
      +local LeaderUnit = UNIT:FindByName( "Leader" )
      +local LargeFormation = AI_FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" )
      +LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 )
      +LargeFormation:__Start( 1 )
       
      @@ -559,6 +586,52 @@ FollowPlanes = AI_FORMATION:New( FollowUnit, FollowGroup, "Desert", "Welcome to + + +
      +
      + + +AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, ZStart, ZSpace) + +
      +
      + +

      FormationCenterWing Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      @@ -780,6 +853,73 @@ self

      + +AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) + +
      +
      + +

      FormationCenterWing Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:OnAfterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) @@ -1036,6 +1176,78 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) + +
      +
      + +

      FormationCenterWing Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + + +
      +
      +
      +
      + AI_FORMATION:OnBeforeFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) @@ -1383,6 +1595,57 @@ If true, then the direction vector will be smoked.

      + +AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace) + +
      +
      + +

      FormationCenterWing Asynchronous Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:__FormationLeftLine(Delay, XStart, YStart, ZStart, ZSpace) @@ -1575,6 +1838,67 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) + +
      +
      + + + +

      Parameters

      +
        +
      • + +

        FollowGroupSet :

        + +
      • +
      • + +

        From :

        + +
      • +
      • + +

        Event :

        + +
      • +
      • + +

        To :

        + +
      • +
      • + +

        XStart :

        + +
      • +
      • + +

        XSpace :

        + +
      • +
      • + +

        YStart :

        + +
      • +
      • + +

        ZStart :

        + +
      • +
      • + +

        ZSpace :

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) diff --git a/docs/Documentation/Database.html b/docs/Documentation/Database.html index 36577a336..1953c3339 100644 --- a/docs/Documentation/Database.html +++ b/docs/Documentation/Database.html @@ -1830,7 +1830,6 @@ self

      - #number DATABASE.UNITS_Position diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 491edc91b..6770c840c 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2478,7 +2478,7 @@ The index of the DetectedItem.

      - #number + DETECTION_BASE.DetectionInterval diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index 9f6365bca..c8c189c3e 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -1624,7 +1624,7 @@ A string defining the start state.

      - + #string FSM._StartState @@ -1923,7 +1923,6 @@ A string defining the start state.

      - FSM.current diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index ab459b6d5..45c002a4d 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -215,7 +215,6 @@ on defined intervals (currently every minute).

      - #number MOVEMENT.AliveUnits @@ -224,9 +223,6 @@ on defined intervals (currently every minute).

      - -

      Contains the counter how many units are currently alive

      -
      diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index b120d2a28..81de94c32 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -2073,9 +2073,6 @@ The group that was spawned. You can use this group for further actions.

      - -

      Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.

      -
      @@ -2529,9 +2526,6 @@ when nothing was spawned.

      - -

      Overwrite unit names by default with group name.

      -
      @@ -2546,9 +2540,6 @@ when nothing was spawned.

      - -

      By default, no InitLimit

      -
      @@ -2584,7 +2575,7 @@ when nothing was spawned.

      - #number + SPAWN.SpawnMaxGroups @@ -2601,7 +2592,7 @@ when nothing was spawned.

      - #number + SPAWN.SpawnMaxUnitsAlive @@ -2929,7 +2920,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
      - #boolean + SPAWN.SpawnUnControlled @@ -2953,7 +2944,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -

      Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.

      +

      When the first Spawn executes, all the Groups need to be made visible before start.

      diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 07dbd4536..3895f8162 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -503,7 +503,7 @@ based on the tasking capabilities defined in Task#TA
      - Core.Cargo#CARGO + Core.Cargo#CARGO_GROUP FSM_PROCESS.Cargo From f8454daf9f60863366f5763390139ccd1f9c8c3e Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 21:17:12 +0200 Subject: [PATCH 27/32] Removed cargo menu is ready. --- Moose Development/Moose/Tasking/Task_CARGO.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 776fe499b..5af0f0b30 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -284,7 +284,7 @@ do -- TASK_CARGO self:__SelectAction( -15 ) - Task:GetMission():GetCommandCenter():MessageToGroup("Cargo menu is ready ...", TaskUnit:GetGroup() ) + --Task:GetMission():GetCommandCenter():MessageToGroup("Cargo menu is ready ...", TaskUnit:GetGroup() ) end --- From ea1b20414543b4952afa0e0b4b1f03c7d2f706ec Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 11 May 2017 21:48:16 +0200 Subject: [PATCH 28/32] Update with correction of angle --- Moose Development/Moose/AI/AI_Formation.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 6dd2c55df..5be95857e 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -630,6 +630,9 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local CT = CT2 - CT1 local CS = ( 3600 / CT ) * ( CD / 1000 ) + + local CDV = { x = CV2.x - CV1.x, y = CV2.y - CV1.y, z = CV2.z - CV1.z } + local Ca = math.atan2( CDV.z, CDV.x ) self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) @@ -646,9 +649,12 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local GS = ( 3600 / GT ) * ( GD / 1000 ) --self:E( { "Group:", GS = GS,GD = GD, GT = GT, GV2 = GV2, GV1 = GV1, GT2 = GT2, GT1 = GT1 } ) + + local GVx = FollowFormation.x * math.cos(Ca) - FollowFormation.z * math.sin(Ca) + local GVz = FollowFormation.z * math.cos(Ca) + FollowFormation.x * math.sin(Ca) -- Calculate the group direction vector - local GV = { x = GV2.x - CV2.x + FollowFormation.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z + FollowFormation.z } + local GV = { x = GV2.x - CV2.x + GVx, y = GV2.y - CV2.y, z = GV2.z - CV2.z + GVz } -- Calculate GH2, GH2 with the same height as CV2. local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } @@ -672,7 +678,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance } -- Now we can calculate the group destination vector GDV. - local GDV = { x = DVu.x * CS * 10 + CVI.x, y = CVI.y, z = DVu.z * CS * 10 + CVI.z } + local GDV = { x = DVu.x * CS + CVI.x, y = CVI.y, z = DVu.z * CS + CVI.z } local ADDx = FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha) local ADDz = FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha) @@ -681,9 +687,9 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) -- local GDV_Formation = GDV local GDV_Formation = { - x = GDV.x + ADDx, + x = GDV.x + GVx, y = GDV.y, - z = GDV.z + ADDz + z = GDV.z + GVz } if self.SmokeDirectionVector == true then From bd75743800504beae9f1107a1817d0d4e797f331 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 12 May 2017 18:39:09 +0200 Subject: [PATCH 29/32] Much improved AI_FORMATION version not the different models supported, but the core logic to route the followers. fiew! Was the whole day busy with this! --- Moose Development/Maths/Distance.ggb | Bin 0 -> 11178 bytes Moose Development/Moose/AI/AI_Formation.lua | 76 +++++++++----------- 2 files changed, 34 insertions(+), 42 deletions(-) create mode 100644 Moose Development/Maths/Distance.ggb diff --git a/Moose Development/Maths/Distance.ggb b/Moose Development/Maths/Distance.ggb new file mode 100644 index 0000000000000000000000000000000000000000..dc32fd5afc04428e387a7d48385f574251da3c85 GIT binary patch literal 11178 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 literal 0 HcmV?d00001 diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 5be95857e..976549720 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -406,7 +406,7 @@ end -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) - self:E( { FollowGroupSet, From , Event ,To, XStart, YStart, ZStart, ZSpace } ) + self:F( { FollowGroupSet, From , Event ,To, XStart, YStart, ZStart, ZSpace } ) FollowGroupSet:Flush() @@ -422,7 +422,6 @@ function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , T PointVec3:SetZ( ZStart + i * ZSpace ) local Vec3 = PointVec3:GetVec3() - self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) FollowGroup:OptionROTPassiveDefense() FollowGroup:OptionROEReturnFire() @@ -444,7 +443,7 @@ end -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) - self:E( { FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace } ) + self:F( { FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace } ) local FollowSet = FollowGroupSet:GetSet() @@ -458,7 +457,6 @@ function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , PointVec3:SetZ( -(ZStart + i * ZSpace) ) local Vec3 = PointVec3:GetVec3() - self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) FollowGroup:OptionROTPassiveDefense() FollowGroup:OptionROEReturnFire() @@ -494,7 +492,6 @@ function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , T PointVec3:SetZ( ZStart + i * ZSpace ) local Vec3 = PointVec3:GetVec3() - self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) FollowGroup:OptionROTPassiveDefense() FollowGroup:OptionROEReturnFire() @@ -530,7 +527,6 @@ function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , PointVec3:SetZ( -(ZStart + i * ZSpace) ) local Vec3 = PointVec3:GetVec3() - self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) FollowGroup:OptionROTPassiveDefense() FollowGroup:OptionROEReturnFire() @@ -565,14 +561,11 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , local Side = ( i % 2 == 0 ) and 1 or -1 local Row = i / 2 + 1 - self:E(Side) - PointVec3:SetX( XStart + Row * XSpace ) PointVec3:SetY( YStart ) PointVec3:SetZ( Side * ( ZStart + i * ZSpace ) ) local Vec3 = PointVec3:GetVec3() - self:E( Vec3 ) FollowGroup:SetState( self, "Vec3", Vec3 ) FollowGroup:OptionROTPassiveDefense() FollowGroup:OptionROEReturnFire() @@ -629,12 +622,10 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5 local CT = CT2 - CT1 - local CS = ( 3600 / CT ) * ( CD / 1000 ) + local CS = ( 3600 / CT ) * ( CD / 1000 ) / 3.6 - local CDV = { x = CV2.x - CV1.x, y = CV2.y - CV1.y, z = CV2.z - CV1.z } - local Ca = math.atan2( CDV.z, CDV.x ) - - self:T2( { "Client:", CS, CD, CT, CV2, CV1, CT2, CT1 } ) + local CDv = { x = CV2.x - CV1.x, y = CV2.y - CV1.y, z = CV2.z - CV1.z } + local Ca = math.atan2( CDv.x, CDv.z ) local GT1 = GroupUnit:GetState( self, "GT1" ) local GT2 = timer.getTime() @@ -646,27 +637,24 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 local GT = GT2 - GT1 - local GS = ( 3600 / GT ) * ( GD / 1000 ) - - --self:E( { "Group:", GS = GS,GD = GD, GT = GT, GV2 = GV2, GV1 = GV1, GT2 = GT2, GT1 = GT1 } ) - - local GVx = FollowFormation.x * math.cos(Ca) - FollowFormation.z * math.sin(Ca) - local GVz = FollowFormation.z * math.cos(Ca) + FollowFormation.x * math.sin(Ca) -- Calculate the group direction vector - local GV = { x = GV2.x - CV2.x + GVx, y = GV2.y - CV2.y, z = GV2.z - CV2.z + GVz } + local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } -- Calculate GH2, GH2 with the same height as CV2. local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } -- Calculate the angle of GV to the orthonormal plane - local alpha = math.atan2( GV.z, GV.x ) + local alpha = math.atan2( GV.x, GV.z ) + local GVx = FollowFormation.z * math.cos( Ca ) + FollowFormation.x * math.sin( Ca ) + local GVz = FollowFormation.x * math.cos( Ca ) - FollowFormation.z * math.sin( Ca ) + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) - local CVI = { x = CV2.x + FollowDistance * math.cos(alpha), + local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), y = GH2.y, -- + FollowFormation.y, - z = CV2.z + FollowDistance * math.sin(alpha), + z = CV2.z + CS * 10 * math.cos(Ca), } -- Calculate the direction vector DV of the escort group. We use CVI as the base and CV2 as the direction. @@ -678,18 +666,15 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local DVu = { x = DV.x / FollowDistance, y = DV.y, z = DV.z / FollowDistance } -- Now we can calculate the group destination vector GDV. - local GDV = { x = DVu.x * CS + CVI.x, y = CVI.y, z = DVu.z * CS + CVI.z } + local GDV = { x = CVI.x, y = CVI.y, z = CVI.z } local ADDx = FollowFormation.x * math.cos(alpha) - FollowFormation.z * math.sin(alpha) local ADDz = FollowFormation.z * math.cos(alpha) + FollowFormation.x * math.sin(alpha) - self:E( { ALPHA = alpha, GDVx = GDV.x, GDVz = GDV.z, ADDx = ADDx, ADDz = ADDz, FOLLOWx = FollowFormation.x, FOLLOWz = FollowFormation.z } ) - --- local GDV_Formation = GDV local GDV_Formation = { - x = GDV.x + GVx, + x = GDV.x - GVx, y = GDV.y, - z = GDV.z + GVz + z = GDV.z - GVz } if self.SmokeDirectionVector == true then @@ -697,28 +682,35 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) trigger.action.smoke( GDV_Formation, trigger.smokeColor.White ) end - -- Measure distance between client and group - local CatchUpDistance = ( ( GDV_Formation.x - GV2.x )^2 + ( GDV_Formation.y - GV2.y )^2 + ( GDV_Formation.z - GV2.z )^2 ) ^ 0.5 - - -- The calculation of the Speed would simulate that the group would take 30 seconds to overcome - -- the requested Distance). - local Time = 10 - local CatchUpSpeed = ( CatchUpDistance - ( CS * 15 ) ) / Time - - local Speed = CS + CatchUpSpeed + + -- Calculate the distance + + local GDv = { x = GV2.x - CV1.x, y = GV2.y - CV1.y, z = GV2.z - CV1.z } + + local Alpha_T = math.atan2( GDv.x, GDv.z ) - math.atan2( CDv.x, CDv.z ) + local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T + local Position = math.cos( Alpha_R ) + local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5 + local Distance = GD * Position + FollowDistance - CS * 2 + + + + local Time = 40 + local Speed = - Distance / Time + local GS = Speed + CS if Speed < 0 then Speed = 0 end - + -- Now route the escort to the desired point with the desired speed. - FollowGroup:RouteToVec3( GDV_Formation, Speed / 3.6 ) -- DCS models speed in Mps (Miles per second) + FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second) end end end, ClientUnit, CT1, CV1, CT2, CV2 ) - self:__Follow( -10 ) + self:__Follow( -2 ) end end From 43598314239aa0ec159f0e22111d2eff70816733 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 May 2017 06:36:13 +0200 Subject: [PATCH 30/32] Updates in POSITIONABLE -- Added :GetBoundingBox() -- Added :GetHeight() -- Updated documentation --- .../Moose/Wrapper/Positionable.lua | 96 ++++++++--- .../bin/TreeHierarchy.csv | 26 +-- docs/Documentation/AI_Patrol.html | 3 + docs/Documentation/Cargo.html | 2 +- docs/Documentation/Designate.html | 1 - docs/Documentation/Detection.html | 2 - docs/Documentation/Fsm.html | 3 +- docs/Documentation/Movement.html | 4 + docs/Documentation/Positionable.html | 151 ++++++++++++------ docs/Documentation/Spawn.html | 2 +- docs/Documentation/Spot.html | 4 - docs/Documentation/Task_Cargo.html | 3 +- docs/Documentation/Zone.html | 8 +- docs/Documentation/index.html | 12 +- 14 files changed, 218 insertions(+), 99 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index c815b7bfb..fa554dad9 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -1,25 +1,4 @@ ---- This module contains the POSITIONABLE class. --- --- 1) @{Positionable#POSITIONABLE} class, extends @{Identifiable#IDENTIFIABLE} --- =========================================================== --- The @{Positionable#POSITIONABLE} class is a wrapper class to handle the POSITIONABLE objects: --- --- * Support all DCS APIs. --- * Enhance with POSITIONABLE specific APIs not in the DCS API set. --- * Manage the "state" of the POSITIONABLE. --- --- 1.1) POSITIONABLE constructor: --- ------------------------------ --- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: --- --- * @{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. +--- **Wrapper** -- This module contains the POSITIONABLE class. -- -- === -- @@ -31,11 +10,34 @@ -- @field #string PositionableName The name of the measurable. -- @field Core.Spot#SPOT Spot The laser Spot. -- @field #number LaserCode The last assigned laser code. + +--- # POSITIONABLE class, extends @{Identifiable#IDENTIFIABLE} +-- +-- The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects: +-- +-- * Support all DCS APIs. +-- * Enhance with POSITIONABLE specific APIs not in the DCS API set. +-- * Manage the "state" of the POSITIONABLE. +-- +-- ## POSITIONABLE constructor +-- +-- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: +-- +-- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- ## 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. +-- +-- +-- @field #POSITIONABLE POSITIONABLE = { ClassName = "POSITIONABLE", PositionableName = "", } - --- A DCSPositionable -- @type DCSPositionable -- @field id_ The ID of the controllable in DCS @@ -207,6 +209,28 @@ function POSITIONABLE:GetVec3() return nil end + +--- Get the bounding box of the underlying POSITIONABLE DCS Object. +-- @param #POSITIONABLE self +-- @return Dcs.DCSTypes#Distance The bounding box of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetBoundingBox() --R2.1 + self:F2() + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionableDesc = DCSPositionable:getDesc() --Dcs.DCSTypes#Desc + if PositionableDesc then + local PositionableBox = PositionableDesc.box + return PositionableBox + end + end + + return nil +end + + --- Returns the altitude of the POSITIONABLE. -- @param Wrapper.Positionable#POSITIONABLE self -- @return Dcs.DCSTypes#Distance The altitude of the POSITIONABLE. @@ -303,6 +327,29 @@ function POSITIONABLE:GetVelocity() return nil end + +--- Returns the POSITIONABLE height in meters. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return Dcs.DCSTypes#Vec3 The height of the positionable. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetHeight() --R2.1 + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local PositionablePosition = DCSPositionable:getPosition() + if PositionablePosition then + local PositionableHeight = PositionablePosition.p.y + self:T2( PositionableHeight ) + return PositionableHeight + end + end + + return nil +end + + --- Returns the POSITIONABLE velocity in km/h. -- @param Wrapper.Positionable#POSITIONABLE self -- @return #number The velocity in km/h @@ -600,3 +647,6 @@ function POSITIONABLE:GetLaserCode() --R2.1 return self.LaserCode end + + + diff --git a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv index 11299e7e5..94fc57631 100644 --- a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv +++ b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv @@ -4,19 +4,19 @@ @K=function, @M=Task_A2G, @N=onafterRouteToTarget, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=6536, @K=function, @M=Task_A2G, @N=onafterRouteToTargets, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_A2G.lua, @C=7408, @K=function, @M=Task_Cargo, @N=onafterSelectAction, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=10439, -@K=function, @M=Task_Cargo, @N=OnLeaveWaitingForCommand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13082, -@K=function, @M=Task_Cargo, @N=onafterRouteToPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13858, -@K=function, @M=Task_Cargo, @N=onafterArriveAtPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=14477, -@K=function, @M=Task_Cargo, @N=onafterRouteToDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15018, -@K=function, @M=Task_Cargo, @N=onafterArriveAtDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15465, -@K=function, @M=Task_Cargo, @N=onafterLand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15895, -@K=function, @M=Task_Cargo, @N=onafterLanded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=16854, -@K=function, @M=Task_Cargo, @N=onafterPrepareBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=17620, -@K=function, @M=Task_Cargo, @N=onafterBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=18080, -@K=function, @M=Task_Cargo, @N=onafterBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19021, -@K=function, @M=Task_Cargo, @N=onafterPrepareUnBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19704, -@K=function, @M=Task_Cargo, @N=onafterUnBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=20664, -@K=function, @M=Task_Cargo, @N=onafterUnBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=21539, +@K=function, @M=Task_Cargo, @N=OnLeaveWaitingForCommand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13084, +@K=function, @M=Task_Cargo, @N=onafterRouteToPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=13860, +@K=function, @M=Task_Cargo, @N=onafterArriveAtPickup, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=14479, +@K=function, @M=Task_Cargo, @N=onafterRouteToDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15020, +@K=function, @M=Task_Cargo, @N=onafterArriveAtDeploy, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15467, +@K=function, @M=Task_Cargo, @N=onafterLand, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=15897, +@K=function, @M=Task_Cargo, @N=onafterLanded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=16856, +@K=function, @M=Task_Cargo, @N=onafterPrepareBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=17622, +@K=function, @M=Task_Cargo, @N=onafterBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=18082, +@K=function, @M=Task_Cargo, @N=onafterBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19023, +@K=function, @M=Task_Cargo, @N=onafterPrepareUnBoarding, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=19706, +@K=function, @M=Task_Cargo, @N=onafterUnBoard, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=20666, +@K=function, @M=Task_Cargo, @N=onafterUnBoarded, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\Tasking\Task_CARGO.lua, @C=21541, @K=function, @M=Designate, @N=OnBeforeLaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12232, @K=function, @M=Designate, @N=OnAfterLaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12480, @K=function, @M=Designate, @N=LaseOn, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=12701, diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index a349f1b11..af53dd252 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -953,6 +953,9 @@ Use the method AIPATROLZONE.M + +

      This table contains the targets detected during patrol.

      +
      diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 8b2fbef53..849e4255a 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -2921,6 +2921,7 @@ The range till cargo will board.

      + CARGO_UNIT.CargoCarrier @@ -3046,7 +3047,6 @@ The range till cargo will board.

      - #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index d8950ff85..9133c530d 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -892,7 +892,6 @@ function below will use the range 1-7 just in case

      - DESIGNATE.LaserCodes diff --git a/docs/Documentation/Detection.html b/docs/Documentation/Detection.html index 6770c840c..b60e01592 100644 --- a/docs/Documentation/Detection.html +++ b/docs/Documentation/Detection.html @@ -2324,7 +2324,6 @@ The index of the DetectedItem.

      - #number DETECTION_BASE.DetectedItemCount @@ -2338,7 +2337,6 @@ The index of the DetectedItem.

      - #number DETECTION_BASE.DetectedItemMax diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index c8c189c3e..9f6365bca 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -1624,7 +1624,7 @@ A string defining the start state.

      - #string + FSM._StartState @@ -1923,6 +1923,7 @@ A string defining the start state.

      + FSM.current diff --git a/docs/Documentation/Movement.html b/docs/Documentation/Movement.html index 45c002a4d..ab459b6d5 100644 --- a/docs/Documentation/Movement.html +++ b/docs/Documentation/Movement.html @@ -215,6 +215,7 @@ on defined intervals (currently every minute).

      + #number MOVEMENT.AliveUnits @@ -223,6 +224,9 @@ on defined intervals (currently every minute).

      + +

      Contains the counter how many units are currently alive

      +
      diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index 196457991..e9d8defe0 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -97,34 +97,10 @@

      Module Positionable

      -

      This module contains the POSITIONABLE class.

      +

      Wrapper -- This module contains the POSITIONABLE class.

      -

      1) Positionable#POSITIONABLE class, extends Identifiable#IDENTIFIABLE

      -

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

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

      1.1) POSITIONABLE constructor:

      -

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

      - - - -

      1.2) POSITIONABLE methods:

      -

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

      - - -
      @@ -133,7 +109,13 @@
      AI_BAIAI_Bai

      AI -- Provide Battlefield Air Interdiction (bombing).

      @@ -166,7 +166,7 @@ even when there are hardly any players in the mission.

      AI_FollowAI_Formation

      AI -- (R2.1) Build large formations of AI Groups flying together.

      AI_FORMATION.FollowUnit +
      AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, ZStart, ZSpace) +

      FormationCenterWing Trigger for AI_FORMATION

      AI_FORMATION:New(FollowUnit, FollowGroupSet, FollowName, FollowBriefing)

      AI_FORMATION class constructor for an AI group

      +
      AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +

      FormationCenterWing Handler OnAfter for AI_FORMATION

      AI_FORMATION:OnAfterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationRightWing Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +

      FormationCenterWing Handler OnBefore for AI_FORMATION

      AI_FORMATION:TestSmokeDirectionVector(SmokeDirection)

      This function is for test, it will put on the frequency of the FollowScheduler a red smoke at the direction vector calculated for the escort to fly to.

      +
      AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace) +

      FormationCenterWing Asynchronous Trigger for AI_FORMATION

      AI_FORMATION:__FormationRightWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationRightWing Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +
      POSITIONABLE +

      POSITIONABLE class, extends Identifiable#IDENTIFIABLE

      +

      The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects:

      + +
        +
      • Support all DCS APIs.
      • +
      @@ -150,12 +132,6 @@

      Type POSITIONABLE

      - - - - + + + + @@ -177,6 +159,12 @@ + + + + @@ -372,6 +360,37 @@
      +

      POSITIONABLE class, extends Identifiable#IDENTIFIABLE

      + +

      The POSITIONABLE class is a wrapper class to handle the POSITIONABLE objects:

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

      POSITIONABLE constructor

      + +

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

      + + + +

      POSITIONABLE methods

      + +

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

      + + +
      @@ -405,20 +424,6 @@
      - #string - -POSITIONABLE.ClassName - -
      -
      - - - -
      -
      -
      -
      - POSITIONABLE:GetAltitude() @@ -465,6 +470,34 @@ Radio

      + +POSITIONABLE:GetBoundingBox() + +
      +
      + +

      Get the bounding box of the underlying POSITIONABLE DCS Object.

      + +

      Return values

      +
        +
      1. + +

        Dcs.DCSTypes#Distance: +The bounding box of the POSITIONABLE.

        + +
      2. +
      3. + +

        #nil: +The POSITIONABLE is not existing or alive.

        + +
      4. +
      +
      +
      +
      +
      + POSITIONABLE:GetCoordinate() @@ -521,6 +554,34 @@ The POSITIONABLE is not existing or alive.

      + +POSITIONABLE:GetHeight() + +
      +
      + +

      Returns the POSITIONABLE height in meters.

      + +

      Return values

      +
        +
      1. + +

        Dcs.DCSTypes#Vec3: +The height of the positionable.

        + +
      2. +
      3. + +

        #nil: +The POSITIONABLE is not existing or alive.

        + +
      4. +
      +
      +
      +
      +
      + POSITIONABLE:GetLaserCode() diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 81de94c32..5c66f6f52 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -2944,7 +2944,7 @@ Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -

      When the first Spawn executes, all the Groups need to be made visible before start.

      +

      Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.

      diff --git a/docs/Documentation/Spot.html b/docs/Documentation/Spot.html index 3ba35dc6d..5befab5b3 100644 --- a/docs/Documentation/Spot.html +++ b/docs/Documentation/Spot.html @@ -763,7 +763,6 @@ true if it is lasing

      - SPOT.ScheduleID @@ -777,7 +776,6 @@ true if it is lasing

      - SPOT.SpotIR @@ -791,7 +789,6 @@ true if it is lasing

      - SPOT.SpotLaser @@ -805,7 +802,6 @@ true if it is lasing

      - SPOT.Target diff --git a/docs/Documentation/Task_Cargo.html b/docs/Documentation/Task_Cargo.html index 3895f8162..deba519e2 100644 --- a/docs/Documentation/Task_Cargo.html +++ b/docs/Documentation/Task_Cargo.html @@ -503,7 +503,7 @@ based on the tasking capabilities defined in Task#TA
      - Core.Cargo#CARGO_GROUP + FSM_PROCESS.Cargo @@ -517,7 +517,6 @@ based on the tasking capabilities defined in Task#TA
      - FSM_PROCESS.DeployZone diff --git a/docs/Documentation/Zone.html b/docs/Documentation/Zone.html index f18faf4f3..38eeb7d9b 100644 --- a/docs/Documentation/Zone.html +++ b/docs/Documentation/Zone.html @@ -97,10 +97,6 @@

      Module Zone

      -

      Core - ZONE classes define zones within your mission of various forms, with various capabilities.

      - - -

      Banner Image


      @@ -109,6 +105,10 @@
      • Test if an object is within the zone boundaries.
      • +
      + + +
      • Provide the zone behaviour. Some zones are static, while others are moveable.
      diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index a5fc2bf03..ec204dbb4 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -433,7 +433,7 @@ are design patterns allowing efficient (long-lasting) processes and workflows.
      @@ -586,7 +586,15 @@ which are excellent tools to be reused in an OO environment!.

      From 755e71f6d9074568e241fd80e259c8cc803bfb8c Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 May 2017 13:29:44 +0200 Subject: [PATCH 31/32] Added -- FormationBox -- FormationTrail -- Optimized formation forming by inclination... --- Moose Development/Moose/AI/AI_Formation.lua | 562 ++++++++++++++++---- 1 file changed, 460 insertions(+), 102 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 976549720..4f9ed5d20 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -5,6 +5,24 @@ -- === -- -- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. +-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! +-- The purpose of the class is to: +-- +-- * Make formation building a process that can be managed while in flight, rather than a task. +-- * Human players can guide formations, consisting of larget planes. +-- * Build large formations (like a large bomber field). +-- * Form formations that DCS does not support off the shelve. +-- +-- A few remarks: +-- +-- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild. +-- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader. +-- * Formations may take a while to build up. +-- +-- As a result, the AI_FORMATION is not perfect, but is very useful to: +-- +-- * Model large formations when flying straight line. +-- * Make humans guide a large formation, when the planes are wide from each other. -- -- There are the following types of classes defined: -- @@ -57,24 +75,49 @@ -- -- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader. -- +-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions. +-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! +-- The purpose of the class is to: +-- +-- * Make formation building a process that can be managed while in flight, rather than a task. +-- * Human players can guide formations, consisting of larget planes. +-- * Build large formations (like a large bomber field). +-- * Form formations that DCS does not support off the shelve. +-- +-- A few remarks: +-- +-- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild. +-- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader. +-- * Formations may take a while to build up. +-- +-- As a result, the AI_FORMATION is not perfect, but is very useful to: +-- +-- * Model large formations when flying straight line. You can build close formations when doing this. +-- * Make humans guide a large formation, when the planes are wide from each other. +-- -- ## AI_FORMATION construction -- -- Create a new SPAWN object with the @{#AI_FORMATION.New} method: -- -- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Group#GROUP} for a @{Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text. -- --- ## Initialization methods +-- ## Formation methods -- --- The following menus are created within the RADIO MENU of an active unit hosted by a player: +-- The following methods can be used to set or change the formation: -- --- * @{AI_Formation#AI_FORMATION.FormationRandom}(): Form a randomized formation (can cause crashed of planes :-)). +-- * @{AI_Formation#AI_FORMATION.FormationLine}(): Form a line formation (core formation function). +-- * @{AI_Formation#AI_FORMATION.FormationTrail}(): Form a trail formation. -- * @{AI_Formation#AI_FORMATION.FormationLeftLine}(): Form a left line formation. -- * @{AI_Formation#AI_FORMATION.FormationRightLine}(): Form a right line formation. -- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation. -- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation. --- * @{AI_Formation#AI_FORMATION.FormationCenterLine}(): Form a center line formation. +-- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation. +-- * @{AI_Formation#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing. -- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation. -- +-- ## Randomization +-- +-- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters. -- -- @usage -- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart() @@ -125,14 +168,144 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin self.FollowUnit = FollowUnit -- Unit#UNIT self.FollowGroupSet = FollowGroupSet -- Set#SET_GROUP + self:SetFlightRandomization( 2 ) + self:SetStartState( "None" ) self:AddTransition( "*", "Stop", "Stopped" ) self:AddTransition( "None", "Start", "Following" ) + + self:AddTransition( "*", "FormationLine", "*" ) + --- FormationLine Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @return #boolean - self:AddTransition( "*", "FormationLeftLine", "*" ) + --- FormationLine Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationLine + -- @param #AI_FORMATION self + -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + --- FormationLine Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationLine + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + --- FormationLine Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationLine + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationTrail", "*" ) + --- FormationTrail Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationTrail + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @return #boolean + + --- FormationTrail Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationTrail + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + + --- FormationTrail Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationTrail + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + + --- FormationTrail Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationTrail + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + + self:AddTransition( "*", "FormationStack", "*" ) + --- FormationStack Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationStack + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @return #boolean + + --- FormationStack Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationStack + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + --- FormationStack Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationStack + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + --- FormationStack Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationStack + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationLeftLine", "*" ) --- FormationLeftLine Handler OnBefore for AI_FORMATION -- @function [parent=#AI_FORMATION] OnBeforeFormationLeftLine -- @param #AI_FORMATION self @@ -174,10 +347,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. - - - self:AddTransition( "*", "FormationRightLine", "*" ) - + + self:AddTransition( "*", "FormationRightLine", "*" ) --- FormationRightLine Handler OnBefore for AI_FORMATION -- @function [parent=#AI_FORMATION] OnBeforeFormationRightLine -- @param #AI_FORMATION self @@ -219,9 +390,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. - + self:AddTransition( "*", "FormationLeftWing", "*" ) - --- FormationLeftWing Handler OnBefore for AI_FORMATION -- @function [parent=#AI_FORMATION] OnBeforeFormationLeftWing -- @param #AI_FORMATION self @@ -268,9 +438,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. - self:AddTransition( "*", "FormationRightWing", "*" ) - --- FormationRightWing Handler OnBefore for AI_FORMATION -- @function [parent=#AI_FORMATION] OnBeforeFormationRightWing -- @param #AI_FORMATION self @@ -317,8 +485,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. - self:AddTransition( "*", "FormationCenterWing", "*" ) - + self:AddTransition( "*", "FormationCenterWing", "*" ) --- FormationCenterWing Handler OnBefore for AI_FORMATION -- @function [parent=#AI_FORMATION] OnBeforeFormationCenterWing -- @param #AI_FORMATION self @@ -329,6 +496,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -- @return #boolean @@ -343,6 +511,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. @@ -352,6 +521,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. @@ -362,12 +532,113 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationVic", "*" ) + --- FormationVic Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationVic + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @return #boolean + + --- FormationVic Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationVic + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + --- FormationVic Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationVic + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + --- FormationVic Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationVic + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + + self:AddTransition( "*", "FormationBox", "*" ) + --- FormationBox Handler OnBefore for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnBeforeFormationBox + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + -- @return #boolean + --- FormationBox Handler OnAfter for AI_FORMATION + -- @function [parent=#AI_FORMATION] OnAfterFormationBox + -- @param #AI_FORMATION self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + --- FormationBox Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] FormationBox + -- @param #AI_FORMATION self + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + + --- FormationBox Asynchronous Trigger for AI_FORMATION + -- @function [parent=#AI_FORMATION] __FormationBox + -- @param #AI_FORMATION self + -- @param #number Delay + -- @param #number XStart The start position on the X-axis in meters for the first group. + -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. + -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. + -- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. + -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. + -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. + -- @param #number ZLevels The amount of levels on the Z-axis. + + self:AddTransition( "*", "Follow", "Following" ) self:FormationLeftLine( 500, 0, 250, 250 ) @@ -394,19 +665,21 @@ function AI_FORMATION:TestSmokeDirectionVector( SmokeDirection ) return self end ---- FormationLeftLine Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationLeftLine +--- FormationLine Handler OnAfter for AI_FORMATION -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From -- @param #string Event -- @param #string To -- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) - self:F( { FollowGroupSet, From , Event ,To, XStart, YStart, ZStart, ZSpace } ) +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) + self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } ) FollowGroupSet:Flush() @@ -417,22 +690,59 @@ function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , T for FollowID, FollowGroup in pairs( FollowSet ) do local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( XStart ) - PointVec3:SetY( YStart ) + PointVec3:SetX( XStart + i * XSpace ) + PointVec3:SetY( YStart + i * YSpace ) PointVec3:SetZ( ZStart + i * ZSpace ) local Vec3 = PointVec3:GetVec3() - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() + FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 end + + return self end +--- FormationTrail Handler OnAfter for AI_FORMATION +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) ---- FormationRightLine Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationRightLine + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,0,0) + + return self +end + + +--- FormationStack Handler OnAfter for AI_FORMATION +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,0,0) + + return self +end + + + + +--- FormationLeftLine Handler OnAfter for AI_FORMATION -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From @@ -442,32 +752,35 @@ end -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) + + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,ZStart,ZSpace) + + return self +end + + +--- FormationRightLine Handler OnAfter for AI_FORMATION +-- @param #AI_FORMATION self +-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #AI_FORMATION function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) - self:F( { FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace } ) - local FollowSet = FollowGroupSet:GetSet() - - local i = 0 - - for FollowID, FollowGroup in pairs( FollowSet ) do - - local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( XStart ) - PointVec3:SetY( YStart ) - PointVec3:SetZ( -(ZStart + i * ZSpace) ) - - local Vec3 = PointVec3:GetVec3() - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() - i = i + 1 - end + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,0,YStart,0,-ZStart,-ZSpace) + return self end --- FormationLeftWing Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationLeftWing -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From @@ -480,24 +793,9 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) - local FollowSet = FollowGroupSet:GetSet() - - local i = 0 - - for FollowID, FollowGroup in pairs( FollowSet ) do - - local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( XStart + i * XSpace ) - PointVec3:SetY( YStart ) - PointVec3:SetZ( ZStart + i * ZSpace ) - - local Vec3 = PointVec3:GetVec3() - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() - i = i + 1 - end + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,ZStart,ZSpace) + return self end @@ -515,29 +813,13 @@ end -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) - local FollowSet = FollowGroupSet:GetSet() - - local i = 0 - - for FollowID, FollowGroup in pairs( FollowSet ) do - - local PointVec3 = POINT_VEC3:New() - PointVec3:SetX( XStart + i * XSpace ) - PointVec3:SetY( YStart ) - PointVec3:SetZ( -(ZStart + i * ZSpace) ) - - local Vec3 = PointVec3:GetVec3() - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() - i = i + 1 - end + self:onafterFormationLine(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,0,-ZStart,-ZSpace) + return self end --- FormationCenterWing Handler OnAfter for AI_FORMATION --- @function [parent=#AI_FORMATION] OnAfterFormationCenterWing -- @param #AI_FORMATION self -- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit. -- @param #string From @@ -546,9 +828,10 @@ end -- @param #number XStart The start position on the X-axis in meters for the first group. -- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. -- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. -- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. -- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. -function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) +function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) local FollowSet = FollowGroupSet:GetSet() @@ -566,15 +849,84 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , PointVec3:SetZ( Side * ( ZStart + i * ZSpace ) ) local Vec3 = PointVec3:GetVec3() - FollowGroup:SetState( self, "Vec3", Vec3 ) - FollowGroup:OptionROTPassiveDefense() - FollowGroup:OptionROEReturnFire() + FollowGroup:SetState( self, "FormationVec3", Vec3 ) + i = i + 1 + end + + return self +end + + +--- FormationVic Handle for AI_FORMATION +-- @param #AI_FORMATION self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationVic( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) + + self:onafterFormationCenterWing(FollowGroupSet,From,Event,To,XStart,XSpace,YStart,YSpace,ZStart,ZSpace) + + return self +end + +--- FormationBox Handler OnAfter for AI_FORMATION +-- @param #AI_FORMATION self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #number XStart The start position on the X-axis in meters for the first group. +-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group. +-- @param #nubmer YStart The start position on the Y-axis in meters for the first group. +-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group. +-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group. +-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group. +-- @param #number ZLevels The amount of levels on the Z-axis. +-- @return #AI_FORMATION +function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels ) + + local FollowSet = FollowGroupSet:GetSet() + + local i = 0 + + for FollowID, FollowGroup in pairs( FollowSet ) do + + local PointVec3 = POINT_VEC3:New() + + local ZIndex = i % ZLevels + local XIndex = math.floor( i / ZLevels ) + local YIndex = math.floor( i / ZLevels ) + + PointVec3:SetX( XStart + XIndex * XSpace ) + PointVec3:SetY( YStart + YIndex * YSpace ) + PointVec3:SetZ( -ZStart - (ZSpace * ZLevels / 2 ) + ZSpace * ZIndex ) + + local Vec3 = PointVec3:GetVec3() + FollowGroup:SetState( self, "FormationVec3", Vec3 ) i = i + 1 end + return self end +--- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation. +-- @param #AI_FORMATION self +-- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters. +-- @return #AI_FORMATION +function AI_FORMATION:SetFlightRandomization( FlightRandomization ) + + self.FlightRandomization = FlightRandomization + + return self +end + --- @param Follow#AI_FORMATION self function AI_FORMATION:onenterFollowing( FollowGroupSet ) @@ -606,10 +958,13 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) FollowGroupSet:ForEachGroup( --- @param Wrapper.Group#GROUP FollowGroup -- @param Wrapper.Unit#UNIT ClientUnit - function( FollowGroup, ClientUnit, CT1, CV1, CT2, CV2 ) + function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 ) + FollowGroup:OptionROTPassiveDefense() + FollowGroup:OptionROEReturnFire() + local GroupUnit = FollowGroup:GetUnit( 1 ) - local FollowFormation = FollowGroup:GetState( self, "Vec3" ) + local FollowFormation = FollowGroup:GetState( self, "FormationVec3" ) if FollowFormation then local FollowDistance = FollowFormation.x @@ -631,18 +986,30 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local GT2 = timer.getTime() local GV1 = GroupUnit:GetState( self, "GV1" ) local GV2 = GroupUnit:GetPointVec3() + GV2:AddX( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) ) + GV2:AddY( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) ) + GV2:AddZ( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) ) GroupUnit:SetState( self, "GT1", GT2 ) GroupUnit:SetState( self, "GV1", GV2 ) + local GD = ( ( GV2.x - GV1.x )^2 + ( GV2.y - GV1.y )^2 + ( GV2.z - GV1.z )^2 ) ^ 0.5 local GT = GT2 - GT1 + + -- Calculate the distance + local GDv = { x = GV2.x - CV1.x, y = GV2.y - CV1.y, z = GV2.z - CV1.z } + local Alpha_T = math.atan2( GDv.x, GDv.z ) - math.atan2( CDv.x, CDv.z ) + local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T + local Position = math.cos( Alpha_R ) + local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5 + local Distance = GD * Position + - CS * 0,5 -- Calculate the group direction vector local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z } -- Calculate GH2, GH2 with the same height as CV2. - local GH2 = { x = GV2.x, y = CV2.y, z = GV2.z } + local GH2 = { x = GV2.x, y = CV2.y + FollowFormation.y, z = GV2.z } -- Calculate the angle of GV to the orthonormal plane local alpha = math.atan2( GV.x, GV.z ) @@ -650,10 +1017,11 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) local GVx = FollowFormation.z * math.cos( Ca ) + FollowFormation.x * math.sin( Ca ) local GVz = FollowFormation.x * math.cos( Ca ) - FollowFormation.z * math.sin( Ca ) + -- Now we calculate the intersecting vector between the circle around CV2 with radius FollowDistance and GH2. -- From the GeoGebra model: CVI = (x(CV2) + FollowDistance cos(alpha), y(GH2) + FollowDistance sin(alpha), z(CV2)) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), - y = GH2.y, -- + FollowFormation.y, + y = GH2.y - ( Distance + FollowFormation.x ) / 5, -- + FollowFormation.y, z = CV2.z + CS * 10 * math.cos(Ca), } @@ -683,20 +1051,10 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) end - -- Calculate the distance - - local GDv = { x = GV2.x - CV1.x, y = GV2.y - CV1.y, z = GV2.z - CV1.z } - local Alpha_T = math.atan2( GDv.x, GDv.z ) - math.atan2( CDv.x, CDv.z ) - local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T - local Position = math.cos( Alpha_R ) - local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5 - local Distance = GD * Position + FollowDistance - CS * 2 + local Time = 60 - - - local Time = 40 - local Speed = - Distance / Time + local Speed = - ( Distance + FollowFormation.x ) / Time local GS = Speed + CS if Speed < 0 then Speed = 0 @@ -707,10 +1065,10 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) end end end, - ClientUnit, CT1, CV1, CT2, CV2 + self, ClientUnit, CT1, CV1, CT2, CV2 ) - self:__Follow( -2 ) + self:__Follow( -0.5 ) end end From 4f806d3e4b4f3c13a266fd12cf7cbaac1a39633a Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 May 2017 13:34:57 +0200 Subject: [PATCH 32/32] Documentation AI_FORMATION --- docs/Documentation/AI_Formation.html | 1954 +++++++++++++++++++++++++- docs/Documentation/AI_Patrol.html | 3 - docs/Documentation/Cargo.html | 2 +- docs/Documentation/Designate.html | 1 + docs/Documentation/Spawn.html | 10 +- docs/Documentation/Zone.html | 8 +- docs/Documentation/index.html | 10 +- 7 files changed, 1912 insertions(+), 76 deletions(-) diff --git a/docs/Documentation/AI_Formation.html b/docs/Documentation/AI_Formation.html index 289db76de..2809b48df 100644 --- a/docs/Documentation/AI_Formation.html +++ b/docs/Documentation/AI_Formation.html @@ -105,7 +105,31 @@
      -

      AI_FORMATION makes AI GROUPs fly in formation of various compositions.

      +

      AI_FORMATION makes AI GROUPs fly in formation of various compositions. +The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! +The purpose of the class is to:

      + +
        +
      • Make formation building a process that can be managed while in flight, rather than a task.
      • +
      • Human players can guide formations, consisting of larget planes.
      • +
      • Build large formations (like a large bomber field).
      • +
      • Form formations that DCS does not support off the shelve.
      • +
      + +

      A few remarks:

      + +
        +
      • Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild.
      • +
      • Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader.
      • +
      • Formations may take a while to build up.
      • +
      + +

      As a result, the AI_FORMATION is not perfect, but is very useful to:

      + +
        +
      • Model large formations when flying straight line.
      • +
      • Make humans guide a large formation, when the planes are wide from each other.
      • +

      There are the following types of classes defined:

      @@ -158,6 +182,12 @@

      Type AI_FORMATION

      POSITIONABLE.ClassName - -
      POSITIONABLE:GetAltitude()

      Returns the altitude of the POSITIONABLE.

      @@ -165,6 +141,12 @@
      POSITIONABLE:GetBeacon()

      Create a Radio#BEACON, to allow this POSITIONABLE to broadcast beacon signals

      +
      POSITIONABLE:GetBoundingBox() +

      Get the bounding box of the underlying POSITIONABLE DCS Object.

      POSITIONABLE:GetHeading()

      Returns the POSITIONABLE heading in degrees.

      +
      POSITIONABLE:GetHeight() +

      Returns the POSITIONABLE height in meters.

      Positionable -

      This module contains the POSITIONABLE class.

      +

      Wrapper -- This module contains the POSITIONABLE class.

      Zone -

      Core - ZONE classes define zones within your mission of various forms, with various capabilities.

      +

      Banner Image

      + +
      + +

      There are essentially two core functions that zones accomodate:

      + +
        +
      • Test if an object is within the zone boundaries.
      • +
      + + + + - + + + + + @@ -215,6 +251,12 @@ + + + + @@ -227,6 +269,24 @@ + + + + + + + + + + + + @@ -236,7 +296,13 @@ - + + + + + @@ -251,6 +317,12 @@ + + + + @@ -266,7 +338,31 @@ - + + + + + + + + + + + + + + + + + @@ -281,6 +377,12 @@ + + + + @@ -293,6 +395,24 @@ + + + + + + + + + + + + @@ -305,6 +425,12 @@ + + + + @@ -320,7 +446,13 @@ - + + + + + @@ -335,6 +467,12 @@ + + + + @@ -350,33 +488,81 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -448,6 +634,32 @@ +

      AI_FORMATION makes AI GROUPs fly in formation of various compositions. +The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! +The purpose of the class is to:

      + +
        +
      • Make formation building a process that can be managed while in flight, rather than a task.
      • +
      • Human players can guide formations, consisting of larget planes.
      • +
      • Build large formations (like a large bomber field).
      • +
      • Form formations that DCS does not support off the shelve.
      • +
      + +

      A few remarks:

      + +
        +
      • Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild.
      • +
      • Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader.
      • +
      • Formations may take a while to build up.
      • +
      + +

      As a result, the AI_FORMATION is not perfect, but is very useful to:

      + +
        +
      • Model large formations when flying straight line. You can build close formations when doing this.
      • +
      • Make humans guide a large formation, when the planes are wide from each other.
      • +
      +

      AI_FORMATION construction

      Create a new SPAWN object with the AI_FORMATION.New method:

      @@ -456,20 +668,25 @@
    • Follow#AI_FORMATION.New(): Creates a new AI_FORMATION object from a Group#GROUP for a Client#CLIENT or a Unit#UNIT, with an optional briefing text.
    • -

      Initialization methods

      +

      Formation methods

      -

      The following menus are created within the RADIO MENU of an active unit hosted by a player:

      +

      The following methods can be used to set or change the formation:

      +

      Randomization

      + +

      Use the method AIFormation#AIFORMATION.SetFlightRandomization() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters.

      Usage:

      @@ -493,6 +710,20 @@ LargeFormation:__Start( 1 )
      + + +AI_FORMATION.FlightRandomization + +
      +
      + + + +
      +
      +
      +
      + #number AI_FORMATION.FollowDistance @@ -586,13 +817,71 @@ LargeFormation:__Start( 1 ) + +
      +
      +
      + + +AI_FORMATION:FormationBox(XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) + +
      +
      + +

      FormationBox Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        #number ZLevels : +The amount of levels on the Z-axis.

        + +
      • +
      -AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, ZStart, ZSpace) +AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, YSpace, ZStart, ZSpace)
      @@ -621,6 +910,12 @@ The start position on the Y-axis in meters for the first group.

    • +

      #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

      + +
    • +
    • +

      #nubmer ZStart : The start position on the Z-axis in meters for the first group.

      @@ -723,6 +1018,58 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:FormationLine(XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationLine Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:FormationRightLine(XStart, YStart, ZStart, ZSpace) @@ -809,6 +1156,132 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:FormationStack(XStart, XSpace, YStart, YSpace) + +
      +
      + +

      FormationStack Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:FormationTrail(XStart, XSpace, YStart) + +
      +
      + +

      FormationTrail Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:FormationVic(XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationVic Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:New(FollowUnit, FollowGroupSet, FollowName, FollowBriefing) @@ -853,8 +1326,81 @@ self

      + +AI_FORMATION:OnAfterFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) + +
      +
      + +

      FormationBox Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        #number ZLevels : +The amount of levels on the Z-axis.

        + +
      • +
      +
      +
      +
      +
      + -AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)
      @@ -904,6 +1450,12 @@ The start position on the Y-axis in meters for the first group.

    • +

      #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

      + +
    • +
    • +

      #nubmer ZStart : The start position on the Z-axis in meters for the first group.

      @@ -1048,6 +1600,79 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:OnAfterFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationLine Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:OnAfterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) @@ -1176,8 +1801,257 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:OnAfterFormationStack(From, Event, To, XStart, XSpace, YStart, YSpace) + +
      +
      + +

      FormationStack Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:OnAfterFormationTrail(From, Event, To, XStart, XSpace, YStart) + +
      +
      + +

      FormationTrail Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:OnAfterFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationVic Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:OnBeforeFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) + +
      +
      + +

      FormationBox Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        #number ZLevels : +The amount of levels on the Z-axis.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + + +
      +
      +
      +
      + -AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)
      @@ -1227,6 +2101,12 @@ The start position on the Y-axis in meters for the first group.

    • +

      #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

      + +
    • +
    • +

      #nubmer ZStart : The start position on the Z-axis in meters for the first group.

      @@ -1381,6 +2261,84 @@ The space between groups on the Z-axis in meters for each sequent group.

      #boolean:

      +
    • +
      +
      +
      + + +AI_FORMATION:OnBeforeFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationLine Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + +
      @@ -1519,6 +2477,192 @@ The space between groups on the Z-axis in meters for each sequent group.

      #boolean:

      + +
      +
      +
      + + +AI_FORMATION:OnBeforeFormationStack(From, Event, To, XStart, XSpace, YStart, YSpace) + +
      +
      + +

      FormationStack Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + + +
      +
      +
      +
      + + +AI_FORMATION:OnBeforeFormationTrail(From, Event, To, XStart, XSpace, YStart) + +
      +
      + +

      FormationTrail Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + + +
      +
      +
      +
      + + +AI_FORMATION:OnBeforeFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationVic Handler OnBefore for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #boolean:

      + +
      @@ -1547,6 +2691,33 @@ The space between groups on the Z-axis in meters for each sequent group.

      If true, nearby targets are reported.

      + +
      +
      +
      + + +AI_FORMATION:SetFlightRandomization(FlightRandomization) + +
      +
      + +

      Use the method AIFormation#AIFORMATION.SetFlightRandomization() to make the air units in your formation randomize their flight a bit while in formation.

      + +

      Parameter

      +
        +
      • + +

        #number FlightRandomization : +The formation flying errors that pilots can make while in formation. Is a range set in meters.

        + +
      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + +
      @@ -1595,8 +2766,71 @@ If true, then the direction vector will be smoked.

      + +AI_FORMATION:__FormationBox(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) + +
      +
      + +

      FormationBox Asynchronous Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        #number ZLevels : +The amount of levels on the Z-axis.

        + +
      • +
      +
      +
      +
      +
      + -AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace) +AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)
      @@ -1630,6 +2864,12 @@ The start position on the Y-axis in meters for the first group.

    • +

      #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

      + +
    • +
    • +

      #nubmer ZStart : The start position on the Z-axis in meters for the first group.

      @@ -1742,6 +2982,63 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:__FormationLine(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationLine Asynchronous Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + AI_FORMATION:__FormationRightLine(Delay, XStart, YStart, ZStart, ZSpace) @@ -1838,59 +3135,295 @@ The space between groups on the Z-axis in meters for each sequent group.

      - -AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) + +AI_FORMATION:__FormationStack(Delay, XStart, XSpace, YStart, YSpace)
      - +

      FormationStack Asynchronous Trigger for AI_FORMATION

      Parameters

      • +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:__FormationTrail(Delay, XStart, XSpace, YStart) + +
      +
      + +

      FormationTrail Asynchronous Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:__FormationVic(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationVic Asynchronous Trigger for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #number Delay :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +
      +
      +
      +
      + + +AI_FORMATION:onafterFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels, FollowGroupSet) + +
      +
      + +

      FormationBox Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        #number ZLevels : +The amount of levels on the Z-axis.

        + +
      • +
      • +

        FollowGroupSet :

      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + + +
      +
      +
      +
      + + +AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationCenterWing Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
      • -

        From :

        +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      • -

        Event :

        +

        #string From :

      • -

        To :

        +

        #string Event :

      • -

        XStart :

        +

        #string To :

      • -

        XSpace :

        +

        #number XStart : +The start position on the X-axis in meters for the first group.

      • -

        YStart :

        +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      • -

        ZStart :

        +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      • -

        ZSpace :

        +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      @@ -1905,51 +3438,61 @@ The space between groups on the Z-axis in meters for each sequent group.

      - +

      FormationLeftLine Handler OnAfter for AI_FORMATION

      Parameters

      • -

        FollowGroupSet :

        +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      • -

        From :

        +

        #string From :

      • -

        Event :

        +

        #string Event :

      • -

        To :

        +

        #string To :

      • -

        XStart :

        +

        #number XStart : +The start position on the X-axis in meters for the first group.

      • -

        YStart :

        +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      • -

        ZStart :

        +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      • -

        ZSpace :

        +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +

      Return value

      + +

      #AI_FORMATION:

      + +
      @@ -1961,53 +3504,59 @@ The space between groups on the Z-axis in meters for each sequent group.

      - +

      FormationLeftWing Handler OnAfter for AI_FORMATION

      Parameters

      • -

        FollowGroupSet :

        +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      • -

        From :

        +

        #string From :

      • -

        Event :

        +

        #string Event :

      • -

        To :

        +

        #string To :

      • -

        XStart :

        +

        #number XStart : +The start position on the X-axis in meters for the first group.

      • -

        XSpace :

        +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

      • -

        YStart :

        +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      • -

        ZStart :

        +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      • -

        ZSpace :

        +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      @@ -2016,57 +3565,145 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:onafterFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) + +
      +
      + +

      FormationLine Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #nubmer YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + + +
      +
      +
      +
      + AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace)
      - +

      FormationRightLine Handler OnAfter for AI_FORMATION

      Parameters

      • -

        FollowGroupSet :

        +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

      • -

        From :

        +

        #string From :

      • -

        Event :

        +

        #string Event :

      • -

        To :

        +

        #string To :

      • -

        XStart :

        +

        #number XStart : +The start position on the X-axis in meters for the first group.

      • -

        YStart :

        +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

      • -

        ZStart :

        +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

      • -

        ZSpace :

        +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

      +

      Return value

      + +

      #AI_FORMATION:

      + +
      @@ -2133,6 +3770,209 @@ The space between groups on the Z-axis in meters for each sequent group.

      + +AI_FORMATION:onafterFormationStack(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace) + +
      +
      + +

      FormationStack Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + + +
      +
      +
      +
      + + +AI_FORMATION:onafterFormationTrail(FollowGroupSet, From, Event, To, XStart, XSpace, YStart) + +
      +
      + +

      FormationTrail Handler OnAfter for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        Core.Set#SET_GROUP FollowGroupSet : +The group AI escorting the FollowUnit.

        + +
      • +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + + +
      +
      +
      +
      + + +AI_FORMATION:onafterFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, FollowGroupSet) + +
      +
      + +

      FormationVic Handle for AI_FORMATION

      + +

      Parameters

      +
        +
      • + +

        #string From :

        + +
      • +
      • + +

        #string Event :

        + +
      • +
      • + +

        #string To :

        + +
      • +
      • + +

        #number XStart : +The start position on the X-axis in meters for the first group.

        + +
      • +
      • + +

        #number XSpace : +The space between groups on the X-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer YStart : +The start position on the Y-axis in meters for the first group.

        + +
      • +
      • + +

        #number YSpace : +The space between groups on the Y-axis in meters for each sequent group.

        + +
      • +
      • + +

        #nubmer ZStart : +The start position on the Z-axis in meters for the first group.

        + +
      • +
      • + +

        #number ZSpace : +The space between groups on the Z-axis in meters for each sequent group.

        + +
      • +
      • + +

        FollowGroupSet :

        + +
      • +
      +

      Return value

      + +

      #AI_FORMATION:

      + + +
      +
      +
      +
      + AI_FORMATION:onenterFollowing(FollowGroupSet) diff --git a/docs/Documentation/AI_Patrol.html b/docs/Documentation/AI_Patrol.html index af53dd252..a349f1b11 100644 --- a/docs/Documentation/AI_Patrol.html +++ b/docs/Documentation/AI_Patrol.html @@ -953,9 +953,6 @@ Use the method AIPATROLZONE.M - -

      This table contains the targets detected during patrol.

      -
      diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index 849e4255a..8b2fbef53 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -2921,7 +2921,6 @@ The range till cargo will board.

      - CARGO_UNIT.CargoCarrier @@ -3047,6 +3046,7 @@ The range till cargo will board.

      + #number CARGO_UNIT.RunCount diff --git a/docs/Documentation/Designate.html b/docs/Documentation/Designate.html index 9133c530d..d8950ff85 100644 --- a/docs/Documentation/Designate.html +++ b/docs/Documentation/Designate.html @@ -892,6 +892,7 @@ function below will use the range 1-7 just in case

      + DESIGNATE.LaserCodes diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 5c66f6f52..19d5a6d46 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -2073,6 +2073,9 @@ The group that was spawned. You can use this group for further actions.

      + +

      Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.

      +
    • @@ -2540,6 +2543,9 @@ when nothing was spawned.

      + +

      By default, no InitLimit

      +
      @@ -2575,7 +2581,7 @@ when nothing was spawned.

      - + #number SPAWN.SpawnMaxGroups @@ -2592,7 +2598,7 @@ when nothing was spawned.

      - + #number SPAWN.SpawnMaxUnitsAlive diff --git a/docs/Documentation/Zone.html b/docs/Documentation/Zone.html index 38eeb7d9b..f18faf4f3 100644 --- a/docs/Documentation/Zone.html +++ b/docs/Documentation/Zone.html @@ -97,6 +97,10 @@

      Module Zone

      +

      Core - ZONE classes define zones within your mission of various forms, with various capabilities.

      + + +

      Banner Image


      @@ -105,10 +109,6 @@
      • Test if an object is within the zone boundaries.
      • -
      - - -
      • Provide the zone behaviour. Some zones are static, while others are moveable.
      diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index ec204dbb4..938f30550 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -586,15 +586,7 @@ which are excellent tools to be reused in an OO environment!.

      AI_FORMATION.FlightRandomization + +
      AI_FORMATION.FollowDistance

      The current follow distance.

      @@ -200,7 +230,13 @@
      AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, ZStart, ZSpace)AI_FORMATION:FormationBox(XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) +

      FormationBox Trigger for AI_FORMATION

      +
      AI_FORMATION:FormationCenterWing(XStart, XSpace, YStart, YSpace, ZStart, ZSpace)

      FormationCenterWing Trigger for AI_FORMATION

      AI_FORMATION:FormationLeftWing(XStart, XSpace, YStart, ZStart, ZSpace)

      FormationLeftWing Trigger for AI_FORMATION

      +
      AI_FORMATION:FormationLine(XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationLine Trigger for AI_FORMATION

      AI_FORMATION:FormationRightWing(XStart, XSpace, YStart, ZStart, ZSpace)

      FormationRightWing Trigger for AI_FORMATION

      +
      AI_FORMATION:FormationStack(XStart, XSpace, YStart, YSpace) +

      FormationStack Trigger for AI_FORMATION

      +
      AI_FORMATION:FormationTrail(XStart, XSpace, YStart) +

      FormationTrail Trigger for AI_FORMATION

      +
      AI_FORMATION:FormationVic(XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationVic Trigger for AI_FORMATION

      AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)AI_FORMATION:OnAfterFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) +

      FormationBox Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnAfterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)

      FormationCenterWing Handler OnAfter for AI_FORMATION

      AI_FORMATION:OnAfterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationLeftWing Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnAfterFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationLine Handler OnAfter for AI_FORMATION

      AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)AI_FORMATION:OnAfterFormationStack(From, Event, To, XStart, XSpace, YStart, YSpace) +

      FormationStack Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnAfterFormationTrail(From, Event, To, XStart, XSpace, YStart) +

      FormationTrail Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnAfterFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationVic Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) +

      FormationBox Handler OnBefore for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)

      FormationCenterWing Handler OnBefore for AI_FORMATION

      AI_FORMATION:OnBeforeFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationLeftWing Handler OnBefore for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationLine Handler OnBefore for AI_FORMATION

      AI_FORMATION:OnBeforeFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationRightWing Handler OnBefore for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationStack(From, Event, To, XStart, XSpace, YStart, YSpace) +

      FormationStack Handler OnBefore for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationTrail(From, Event, To, XStart, XSpace, YStart) +

      FormationTrail Handler OnBefore for AI_FORMATION

      +
      AI_FORMATION:OnBeforeFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationVic Handler OnBefore for AI_FORMATION

      AI_FORMATION.ReportTargets

      If true, nearby targets are reported.

      +
      AI_FORMATION:SetFlightRandomization(FlightRandomization) +

      Use the method AIFormation#AIFORMATION.SetFlightRandomization() to make the air units in your formation randomize their flight a bit while in formation.

      AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)AI_FORMATION:__FormationBox(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels) +

      FormationBox Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:__FormationCenterWing(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace)

      FormationCenterWing Asynchronous Trigger for AI_FORMATION

      AI_FORMATION:__FormationLeftWing(Delay, XStart, XSpace, YStart, ZStart, ZSpace)

      FormationLeftWing Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:__FormationLine(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationLine Asynchronous Trigger for AI_FORMATION

      AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace)AI_FORMATION:__FormationStack(Delay, XStart, XSpace, YStart, YSpace) - +

      FormationStack Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:__FormationTrail(Delay, XStart, XSpace, YStart) +

      FormationTrail Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:__FormationVic(Delay, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationVic Asynchronous Trigger for AI_FORMATION

      +
      AI_FORMATION:onafterFormationBox(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, ZLevels, FollowGroupSet) +

      FormationBox Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:onafterFormationCenterWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationCenterWing Handler OnAfter for AI_FORMATION

      AI_FORMATION:onafterFormationLeftLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) - +

      FormationLeftLine Handler OnAfter for AI_FORMATION

      AI_FORMATION:onafterFormationLeftWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) - +

      FormationLeftWing Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:onafterFormationLine(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace) +

      FormationLine Handler OnAfter for AI_FORMATION

      AI_FORMATION:onafterFormationRightLine(FollowGroupSet, From, Event, To, XStart, YStart, ZStart, ZSpace) - +

      FormationRightLine Handler OnAfter for AI_FORMATION

      AI_FORMATION:onafterFormationRightWing(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, ZStart, ZSpace) +
      AI_FORMATION:onafterFormationStack(FollowGroupSet, From, Event, To, XStart, XSpace, YStart, YSpace) +

      FormationStack Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:onafterFormationTrail(FollowGroupSet, From, Event, To, XStart, XSpace, YStart) +

      FormationTrail Handler OnAfter for AI_FORMATION

      +
      AI_FORMATION:onafterFormationVic(From, Event, To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, FollowGroupSet) +

      FormationVic Handle for AI_FORMATION

      Zone -

      Banner Image

      - -
      - -

      There are essentially two core functions that zones accomodate:

      - -
        -
      • Test if an object is within the zone boundaries.
      • -
      +

      Core - ZONE classes define zones within your mission of various forms, with various capabilities.