diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index dd8fa50c9..e85af0540 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -1,36 +1,69 @@ ---- This module contains the AI_BALANCER class. +--- SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class. +-- +-- AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an +-- engaging simulation environment, even when there are hardly any players in the mission. +-- +-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) -- -- === -- --- 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} --- =================================================================================== +-- # 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} +-- -- The @{AI.AI_Balancer#AI_BALANCER} class monitors and manages as many AI GROUPS as there are --- CLIENTS in a SET_CLIENT collection not occupied by players. +-- CLIENTS in a SET_CLIENT collection not occupied by human players. +-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI. +-- -- The AI_BALANCER class manages internally a collection of AI management objects, which govern the behaviour --- of the underlying AI GROUPS. +-- of the spawned AI @{Wrapper.Group#GROUP)s. -- -- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM) -- and calls for each event the state transition methods providing the internal @{Core.Fsm#FSM_SET.Set} object containing the --- SET_GROUP and additional event parameters provided during the event. +-- AI and additional event parameters provided during the event. -- --- 1.1) AI_BALANCER construction method --- --------------------------------------- --- Create a new AI_BALANCER object with the @{#AI_BALANCER.New} method: +-- ## 1.1) AI_BALANCER construction -- --- * @{#AI_BALANCER.New}: Creates a new AI_BALANCER object. +-- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: +-- +-- ## 1.2) AI_BALANCER is a FSM +-- +-- The AI_BALANCER is a state machine: it manages the different events and states of the @{Core.Fsm#FSM_SET.Set} it is governing. +-- The AI_BALANCER has a default flow to manage the set. +-- +-- ![Process](..\Presentations\AI_Balancer\Dia2.JPG) +-- +-- +-- ### 1.2.1) AI_BALANCER States +-- +-- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. +-- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. +-- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. +-- +-- ### 1.2.2) AI_BALANCER Events +-- +-- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. +-- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. +-- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. -- --- 1.2) --- ---- --- * Add --- * Remove +-- ## 1.3) AI_BALANCER spawn interval for replacement AI -- --- 1.2) AI_BALANCER returns AI to Airbases --- ------------------------------------------ --- You can configure to have the AI to return to: +-- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. -- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. --- -- +-- ## 1.4) AI_BALANCER returns AI to Airbases +-- +-- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. +-- However, there are 2 additional options that you can use to customize the destroy behaviour. +-- When a human player joins a slot, you can configure to let the AI return to: +-- +-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. +-- +-- Note that when AI returns to an airbase, it will trigger the **Return** event and will return, +-- otherwise when the AI is destroyed, the **Destroy** event will be triggered. +-- -- === -- -- **API CHANGE HISTORY** @@ -43,29 +76,21 @@ -- -- Hereby the change log: -- --- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. -- -- === -- --- AUTHORS and CONTRIBUTIONS --- ========================= +-- # **AUTHORS and CONTRIBUTIONS** -- -- ### Contributions: -- --- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. --- Working together with James has resulted in the creation of the AI_BALANCER class. --- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) -- --- * **SNAFU**: --- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. --- None of the script code has been used however within the new AI_BALANCER moose class. +-- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. -- -- ### Authors: -- --- * FlightControl: Framework Design & Programming +-- * FlightControl: Framework Design & Programming and Documentation. -- -- @module AI_Balancer @@ -74,47 +99,64 @@ --- AI_BALANCER class -- @type AI_BALANCER -- @field Core.Set#SET_CLIENT SetClient +-- @field Functional.Spawn#SPAWN SpawnAI +-- @field Wrapper.Group#GROUP Test -- @extends Core.Fsm#FSM_SET AI_BALANCER = { ClassName = "AI_BALANCER", PatrolZones = {}, AIGroups = {}, + Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. + Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. } + + --- Creates a new AI_BALANCER object -- @param #AI_BALANCER self -- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). -- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. -- @return #AI_BALANCER --- @usage --- -- Define a new AI_BALANCER Object. function AI_BALANCER:New( SetClient, SpawnAI ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- Core.Fsm#FSM_SET + local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER self:SetStartState( "None" ) - self:AddTransition( "*", "Start", "Monitoring" ) self:AddTransition( "*", "Monitor", "Monitoring" ) self:AddTransition( "*", "Spawn", "Spawning" ) self:AddTransition( "Spawning", "Spawned", "Spawned" ) self:AddTransition( "*", "Destroy", "Destroying" ) self:AddTransition( "*", "Return", "Returning" ) - self:AddTransition( "*", "End", "End" ) - self:AddTransition( "*", "Dead", "End" ) - - self.SetClient = SetClient + self.SetClient:FilterOnce() self.SpawnAI = SpawnAI + + self.SpawnQueue = {} + self.ToNearestAirbase = false self.ToHomeAirbase = false - self:__Start( 1 ) + self:__Monitor( 1 ) return self end +--- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. +-- Provide 2 identical seconds if the interval should be a fixed amount of seconds. +-- @param #AI_BALANCER self +-- @param #number Earliest The earliest a new AI can be spawned in seconds. +-- @param #number Latest The latest a new AI can be spawned in seconds. +-- @return self +function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) + + self.Earliest = Earliest + self.Latest = Latest + + return self +end + --- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self -- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. @@ -142,23 +184,27 @@ end function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) -- OK, Spawn a new group from the default SpawnAI object provided. - local AIGroup = self.SpawnAI:Spawn() + local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP AIGroup:E( "Spawning new AIGroup" ) --TODO: need to rework UnitName thing ... SetGroup:Add( ClientName, AIGroup ) + self.SpawnQueue[ClientName] = nil -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) + self:Spawned( AIGroup ) end --- @param #AI_BALANCER self -- @param Core.Set#SET_GROUP SetGroup -- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, AIGroup ) +function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) AIGroup:Destroy() + SetGroup:Flush() + SetGroup:Remove( ClientName ) + SetGroup:Flush() end --- @param #AI_BALANCER self @@ -190,18 +236,22 @@ end --- @param #AI_BALANCER self function AI_BALANCER:onenterMonitoring( SetGroup ) + self:E( { self.SetClient:Count() } ) + self.SetClient:Flush() + self.SetClient:ForEachClient( --- @param Wrapper.Client#CLIENT Client function( Client ) self:E(Client.ClientName) local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP + self:E({Client:IsAlive()}) if Client:IsAlive() then if AIGroup and AIGroup:IsAlive() == true then if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - self:Destroy( AIGroup ) + self:Destroy( Client.UnitName, AIGroup ) else -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. -- If there is a CLIENT, the AI stays engaged and will not return. @@ -240,9 +290,13 @@ function AI_BALANCER:onenterMonitoring( SetGroup ) end else if not AIGroup or not AIGroup:IsAlive() == true then - self:E("client not alive") - self:Spawn( Client.UnitName ) - self:E("text after spawn") + self:E( "Client " .. Client.UnitName .. " not alive." ) + if not self.SpawnQueue[Client.UnitName] then + -- Spawn a new AI taking into account the spawn interval Earliest, Latest + self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) + self.SpawnQueue[Client.UnitName] = true + self:E( "New AI Spawned for Client " .. Client.UnitName ) + end end end return true diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index eeecd3226..e8963c927 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -42,14 +42,14 @@ -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. -- There are 2 moments when state transition methods will be called by the state machine: -- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- * **Leaving** the state. +-- The state transition method needs to start with the name **OnLeave + the name of the state**. -- If the state transition method returns false, then the processing of the state transition will not be done! -- If you want to change the behaviour of the AIControllable at this event, return false, -- but then you'll need to specify your own logic using the AIControllable! -- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- * **Entering** the state. +-- The state transition method needs to start with the name **OnEnter + the name of the state**. -- These state transition methods need to provide a return value, which is specified at the function description. -- -- 2) #AI_CARGO_UNIT class @@ -135,45 +135,45 @@ -- UnLoaded ---- @function [parent=#AI_CARGO] OnBeforeUnLoaded +--- @function [parent=#AI_CARGO] OnLeaveUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnLoaded +--- @function [parent=#AI_CARGO] OnEnterUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Loaded ---- @function [parent=#AI_CARGO] OnBeforeLoaded +--- @function [parent=#AI_CARGO] OnLeaveLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterLoaded +--- @function [parent=#AI_CARGO] OnEnterLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Boarding ---- @function [parent=#AI_CARGO] OnBeforeBoarding +--- @function [parent=#AI_CARGO] OnLeaveBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterBoarding +--- @function [parent=#AI_CARGO] OnEnterBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- UnBoarding ---- @function [parent=#AI_CARGO] OnBeforeUnBoarding +--- @function [parent=#AI_CARGO] OnLeaveUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnBoarding +--- @function [parent=#AI_CARGO] OnEnterUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 0f060855a..2d1948aee 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -310,7 +310,7 @@ do -- FSM function FSM:New( FsmT ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + self = BASE:Inherit( self, BASE:New() ) self.options = options or {} self.options.subs = self.options.subs or {} @@ -537,17 +537,17 @@ do -- FSM self:E( { EventName, ... } ) - local can, to = self:can( EventName ) - self:E( { EventName, self.current, can, to } ) + local Can, to = self:can( EventName ) + self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) - local ReturnValues = nil - - if can then + if Can then local from = self.current local params = { from, EventName, to, ... } if self:_call_handler("onbefore" .. EventName, params) == false - or self:_call_handler("onleave" .. from, params) == false then + or self:_call_handler("OnBefore" .. EventName, params) == false + or self:_call_handler("onleave" .. from, params) == false + or self:_call_handler("OnLeave" .. from, params) == false then return false end @@ -565,14 +565,16 @@ do -- FSM sub.fsm.fsmparent = self sub.fsm.ReturnEvents = sub.ReturnEvents sub.fsm[sub.StartEvent]( sub.fsm ) - execute = true + execute = false end local fsmparent, Event = self:_isendstate( to ) if fsmparent and Event then self:F2( { "end state: ", fsmparent, Event } ) self:_call_handler("onenter" .. to, params) + self:_call_handler("OnEnter" .. to, params) self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) fsmparent[Event]( fsmparent ) execute = false @@ -580,25 +582,16 @@ do -- FSM if execute then -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! - if from ~= to then - self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) + --if from ~= to then self:_call_handler("onenter" .. to, params) - end + self:_call_handler("OnEnter" .. to, params) + --end - self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) - if ( self:_call_handler("OnBefore" .. to, params ) ~= false ) then - - self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) - self:_call_handler("onafter" .. EventName, params) - - self:T3( { On = "OnAfter" .. EventName, callback = self["OnAfter" .. EventName] } ) - ReturnValues = self:_call_handler("OnAfter" .. EventName, params ) - end + self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) end - - return ReturnValues end return nil @@ -1007,7 +1000,7 @@ do -- FSM_SET function FSM_SET:New( FSMSet ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET + self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET if FSMSet then self:Set( FSMSet ) diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index b34ffd782..18ac50a5a 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -68,14 +68,14 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr if Scheduler.SchedulerObject then self.ObjectSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.ObjectSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), SchedulerObject = tostring(Scheduler.SchedulerObject) } ) else self.PersistentSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.PersistentSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) end self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) - self.Schedule[Scheduler] = {} + self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} self.Schedule[Scheduler][self.CallID] = {} self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index 6047240aa..14b596a5b 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -96,7 +96,11 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume self:F2( { Start, Repeat, RandomizeFactor, Stop } ) self:T3( { SchedulerArguments } ) - + local ObjectName = "-" + if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then + ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID + end + self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) self.SchedulerObject = SchedulerObject local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index ed94d776b..f20832639 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -233,6 +233,7 @@ -- @field #table Filter -- @field #table Set -- @field #table List +-- @field Core.Scheduler#SCHEDULER CallScheduler -- @extends Core.Base#BASE SET_BASE = { ClassName = "SET_BASE", @@ -250,7 +251,7 @@ SET_BASE = { function SET_BASE:New( Database ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE self.Database = Database @@ -260,6 +261,8 @@ function SET_BASE:New( Database ) self.List = {} self.List.__index = self.List self.List = setmetatable( { Count = 0 }, self.List ) + + self.CallScheduler = SCHEDULER:New( self ) return self end @@ -647,7 +650,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen return false end - local Scheduler = SCHEDULER:New( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) + self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) return self end diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index b5812fffa..843b12f0e 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -207,6 +207,7 @@ SPAWN = { SpawnAliasPrefix = nil, } + --- @type SPAWN.SpawnZoneTable -- @list SpawnZone diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index a5ba2121e..1115e8869 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -883,4 +883,3 @@ function GROUP:CalculateThreatLevelA2G() end - diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index 3ac441fbd..ed00a0cfe 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -34,7 +34,6 @@ OBJECT = { ObjectName = "", } - --- A DCSObject -- @type DCSObject -- @field id_ The ID of the controllable in DCS @@ -43,10 +42,11 @@ OBJECT = { -- @param #OBJECT self -- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name -- @return #OBJECT self -function OBJECT:New( ObjectName ) +function OBJECT:New( ObjectName, Test ) local self = BASE:Inherit( self, BASE:New() ) self:F2( ObjectName ) self.ObjectName = ObjectName + return self end diff --git a/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat b/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat index 7db429fef..5ccbaab56 100644 --- a/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat +++ b/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat @@ -5,4 +5,19 @@ rem Provide as the only parameter the path to the .miz files, which can be embed echo Path to Mission Files: %1 -For /R %1 %%G IN (*.miz) do 7z u "%%G" "l10n\DEFAULT\Moose.lua" +rem For /R %1 %%G IN (*.miz) do 7z u "%%G" "l10n\DEFAULT\Moose.lua" +For /R %1 %%M IN (*.miz) do ( + echo off + cd + echo "Mission: %%M" + mkdir Temp + cd Temp + mkdir l10n + mkdir l10n\DEFAULT + copy ..\..\Moose.lua l10n\DEFAULT + copy "%%~pM%%~nM.lua" l10n\DEFAULT\*.* + dir l10n\DEFAULT + 7z -bb0 u "%%M" "l10n\DEFAULT\*.lua" + cd .. + rmdir /S /Q Temp +) \ No newline at end of file diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua index 0624636f1..e91c2183c 100644 --- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua +++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170105_0841' ) +env.info( 'Moose Generation Timestamp: 20170108_2104' ) local base = _G Include = {} @@ -3884,7 +3884,11 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume self:F2( { Start, Repeat, RandomizeFactor, Stop } ) self:T3( { SchedulerArguments } ) - + local ObjectName = "-" + if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then + ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID + end + self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) self.SchedulerObject = SchedulerObject local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( @@ -4013,14 +4017,14 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr if Scheduler.SchedulerObject then self.ObjectSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.ObjectSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), SchedulerObject = tostring(Scheduler.SchedulerObject) } ) else self.PersistentSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.PersistentSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) end self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) - self.Schedule[Scheduler] = {} + self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} self.Schedule[Scheduler][self.CallID] = {} self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments @@ -7667,6 +7671,7 @@ end -- @field #table Filter -- @field #table Set -- @field #table List +-- @field Core.Scheduler#SCHEDULER CallScheduler -- @extends Core.Base#BASE SET_BASE = { ClassName = "SET_BASE", @@ -7684,7 +7689,7 @@ SET_BASE = { function SET_BASE:New( Database ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE self.Database = Database @@ -7694,6 +7699,8 @@ function SET_BASE:New( Database ) self.List = {} self.List.__index = self.List self.List = setmetatable( { Count = 0 }, self.List ) + + self.CallScheduler = SCHEDULER:New( self ) return self end @@ -8081,7 +8088,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen return false end - local Scheduler = SCHEDULER:New( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) + self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) return self end @@ -10699,50 +10706,85 @@ end ----- The _MessageQueue object is created when the MESSAGE class module is loaded. ----_MessageQueue = MESSAGEQUEUE:New( 0.5 ) -- ---- This module contains the FSM class and derived FSM_ classes. +--- This module contains the **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes. +-- ## Finite State Machines (FSM) are design patterns allowing efficient (long-lasting) processes and workflows. +-- +-- ![Banner Image](..\Presentations\FSM\Dia1.JPG) +-- +-- A FSM can only be in one of a finite number of states. +-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. +-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. +-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. +-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. +-- +-- The FSM class supports a **hierarchical implementation of a Finite State Machine**, +-- that is, it allows to **embed existing FSM implementations in a master FSM**. +-- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. +-- +-- ![Workflow Example](..\Presentations\FSM\Dia2.JPG) +-- +-- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, +-- orders him to destroy x targets and account the results. +-- Other examples of ready made FSM could be: +-- +-- * route a plane to a zone flown by a human +-- * detect targets by an AI and report to humans +-- * account for destroyed targets by human players +-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle +-- * let an AI patrol a zone +-- +-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, +-- because **the goal of MOOSE is to simplify mission design complexity for mission building**. +-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. +-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, +-- and tailored** by mission designers through **the implementation of Transition Handlers**. +-- Each of these FSM implementation classes start either with: +-- +-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. +-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. +-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. +-- +-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. +-- +-- ##__Dislaimer:__ +-- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. +-- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) +-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. +-- Additionally, I've added extendability and created an API that allows seamless FSM implementation. -- --- This development is based on a state machine implementation made by Conroy Kyle. --- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine --- --- I've taken the development and enhanced it (actually rewrote it) to make the state machine hierarchical... --- It is a fantastic development, this module. --- -- === -- --- ![Banner Image](..\Presentations\FSM\Dia1.jpg) --- -- # 1) @{Core.Fsm#FSM} class, extends @{Core.Base#BASE} -- --- A Finite State Machine (FSM) defines the rules of transitioning between various States triggered by Events. +-- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG) -- --- * A **State** defines a moment in the process. --- * An **Event** describes an action, that can be triggered both internally as externally in the FSM. +-- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. +-- The derived FSM\_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component. -- --- ## 1.1) Event Handling +-- Finite State Machines have **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- --- ![Event Handlers](..\Presentations\FSM\Dia3.jpg) +-- The **Transition Rules** define the "Process Flow Boundaries", that is, +-- the path that can be followed hopping from state to state upon triggered events. +-- If an event is triggered, and there is no valid path found for that event, +-- an error will be raised and the FSM will stop functioning. -- --- An FSM transitions in **4 moments** when an Event is being handled. --- Each moment can be catched by handling methods defined by the mission designer, --- that will be called by the FSM while executing the transition. --- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be fired. --- --- * To handle **State** moments, create methods starting with OnLeave or OnEnter concatenated with the State name. --- * To handle **Event** moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. +-- The **Transition Handlers** are special methods that can be defined by the mission designer, following a defined syntax. +-- If the FSM object finds a method of such a handler, then the method will be called by the FSM, passing specific parameters. +-- The method can then define its own custom logic to implement the FSM workflow, and to conduct other actions. -- --- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition.** +-- The **Event Triggers** are methods that are defined by the FSM, which the mission designer can use to implement the workflow. +-- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. -- --- ## 1.2) Event Triggers +-- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. +-- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- --- ![Event Triggers](..\Presentations\FSM\Dia4.jpg) +-- ## 1.1) FSM Linear Transitions -- --- The FSM creates for each Event **two Event Trigger methods**. --- There are two modes how Events can be triggered, which is **embedded** and **delayed**: +-- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. +-- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. +-- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. -- --- * The method **FSM:Event()** triggers an Event that will be processed **embedded** or **immediately**. --- * The method **FSM:__Event( seconds )** triggers an Event that will be processed **delayed** over time, waiting x seconds. --- --- ## 1.3) FSM Transition Rules +-- ### 1.1.1) FSM Transition Rules -- -- The FSM has transition rules that it follows and validates, as it walks the process. -- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. @@ -10751,12 +10793,107 @@ end -- -- The initial state can be defined using the method @{#FSM.SetStartState}(). The default start state of an FSM is "None". -- --- ### Example +-- Find below an example of a Linear Transition Rule definition for an FSM. -- --- This example creates a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to Green. --- 2 Transition Rules are created, where upon the event Switch, --- the FsmDemo will transition from state Green to Red and vise versa. +-- local Fsm3Switch = FSM:New() -- #FsmDemo +-- FsmSwitch:SetStartState( "Off" ) +-- FsmSwitch:AddTransition( "Off", "SwitchOn", "On" ) +-- FsmSwitch:AddTransition( "Off", "SwitchMiddle", "Middle" ) +-- FsmSwitch:AddTransition( "On", "SwitchOff", "Off" ) +-- FsmSwitch:AddTransition( "Middle", "SwitchOff", "Off" ) +-- +-- The above code snippet models a 3-way switch Linear Transition: +-- +-- * It can be switched **On** by triggering event **SwitchOn**. +-- * It can be switched to the **Middle** position, by triggering event **SwitchMiddle**. +-- * It can be switched **Off** by triggering event **SwitchOff**. +-- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. +-- +-- ### Some additional comments: +-- +-- Note that Linear Transition Rules **can be declared in a few variations**: +-- +-- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. +-- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. +-- +-- The below code snippet shows how the two last lines can be rewritten and consensed. +-- +-- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) +-- +-- ### 1.1.2) Transition Handling +-- +-- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG) +-- +-- An FSM transitions in **4 moments** when an Event is being triggered and processed. +-- The mission designer can define for each moment specific logic within methods implementations following a defined API syntax. +-- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be triggered. +-- +-- * To handle **State** transition moments, create methods starting with OnLeave or OnEnter concatenated with the State name. +-- * To handle **Event** transition moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. +-- +-- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition!** +-- +-- Transition Handler methods need to follow the above specified naming convention, but are also passed parameters from the FSM. +-- These parameters are on the correct order: From, Event, To: +-- +-- * From = A string containing the From state. +-- * Event = A string containing the Event name that was triggered. +-- * To = A string containing the To state. +-- +-- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). +-- +-- ### 1.1.3) Event Triggers +-- +-- ![Event Triggers](..\Presentations\FSM\Dia5.JPG) +-- +-- The FSM creates for each Event two **Event Trigger methods**. +-- There are two modes how Events can be triggered, which is **synchronous** and **asynchronous**: +-- +-- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. +-- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. +-- +-- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. +-- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. +-- +-- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. +-- +-- function FSM:OnAfterEvent( From, Event, To, Amount ) +-- self:E( { Amount = Amount } ) +-- end +-- +-- local Amount = 1 +-- FSM:__Event( 5, Amount ) +-- +-- Amount = Amount + 1 +-- FSM:Event( Text, Amount ) +-- +-- In this example, the **:OnAfterEvent**() Transition Handler implementation will get called when **Event** is being triggered. +-- Before we go into more detail, let's look at the last 4 lines of the example. +-- The last line triggers synchronously the **Event**, and passes Amount as a parameter. +-- The 3rd last line of the example triggers asynchronously **Event**. +-- Event will be processed after 5 seconds, and Amount is given as a parameter. +-- +-- The output of this little code fragment will be: +-- +-- * Amount = 2 +-- * Amount = 2 +-- +-- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! +-- +-- ### 1.1.4) Linear Transition Example +-- +-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) +-- +-- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare. +-- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build. +-- Have a look at the source code. The source code is also further explained below in this section. +-- +-- The example creates a new FsmDemo object from class FSM. +-- It will set the start state of FsmDemo to state **Green**. +-- Two Linear Transition Rules are created, where upon the event **Switch**, +-- the FsmDemo will transition from state **Green** to **Red** and from **Red** back to **Green**. +-- +-- ![Transition Example](..\Presentations\FSM\Dia6.JPG) -- -- local FsmDemo = FSM:New() -- #FsmDemo -- FsmDemo:SetStartState( "Green" ) @@ -10766,6 +10903,8 @@ end -- In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. -- The next code implements this through the event handling method **OnAfterSwitch**. -- +-- ![Transition Flow](..\Presentations\FSM\Dia7.JPG) +-- -- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) -- self:E( { From, Event, To, FsmUnit } ) -- @@ -10776,7 +10915,7 @@ end -- FsmUnit:Flare(FLARECOLOR.Red) -- end -- end --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. +-- self:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. -- end -- -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds. @@ -10806,20 +10945,9 @@ end -- -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. -- --- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) --- --- ### Some additional comments: --- --- Note that transition rules can be declared with a few variations: --- --- * The From states can be a table of strings, indicating that the transition rule will be valid if the current state of the FSM will be one of the given From states. --- * The From state can be a "*", indicating that the transition rule will always be valid, regardless of the current state of the FSM. --- --- This transition will create a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to Green. --- A new event is added in addition to the above example. --- The new event Stop will cancel the Switching process. --- So, the transtion for event Stop can be executed if the current state of the FSM is either "Red" or "Green". +-- The below code fragment extends the FsmDemo, demonstrating multiple **From states declared as a table**, adding a **Linear Transition Rule**. +-- The new event **Stop** will cancel the Switching process. +-- The transition for event Stop can be executed if the current state of the FSM is either "Red" or "Green". -- -- local FsmDemo = FSM:New() -- #FsmDemo -- FsmDemo:SetStartState( "Green" ) @@ -10830,15 +10958,20 @@ end -- The transition for event Stop can also be simplified, as any current state of the FSM is valid. -- -- FsmDemo:AddTransition( "*", "Stop", "Stopped" ) +-- +-- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. +-- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. -- --- ## 1.4) FSM Process Rules +-- ## 1.5) FSM Hierarchical Transitions -- --- The FSM can implement sub-processes that will execute and return multiple possible states. --- Depending upon which state is returned, the main FSM can continue tiggering different events. +-- Hierarchical Transitions allow to re-use readily available and implemented FSMs. +-- This becomes in very useful for mission building, where mission designers build complex processes and workflows, +-- combining smaller FSMs to one single FSM. -- --- The method @{#FSM.AddProcess}() adds a new Sub-Process FSM to the FSM. --- A Sub-Process will start the Sub-Process of the FSM upon the defined triggered Event, --- with multiple possible States as a result. +-- The FSM can embed **Sub-FSMs** that will execute and return **multiple possible Return (End) States**. +-- Depending upon **which state is returned**, the main FSM can continue the flow **triggering specific events**. +-- +-- The method @{#FSM.AddProcess}() adds a new Sub-FSM to the FSM. -- -- ==== -- @@ -10862,11 +10995,11 @@ end -- -- ### Contributions: -- --- * None. +-- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements. -- -- ### Authors: -- --- * **FlightControl**: Design & Programming +-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. -- -- @module Fsm @@ -10885,7 +11018,7 @@ do -- FSM function FSM:New( FsmT ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + self = BASE:Inherit( self, BASE:New() ) self.options = options or {} self.options.subs = self.options.subs or {} @@ -11112,17 +11245,17 @@ do -- FSM self:E( { EventName, ... } ) - local can, to = self:can( EventName ) - self:E( { EventName, self.current, can, to } ) + local Can, to = self:can( EventName ) + self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) - local ReturnValues = nil - - if can then + if Can then local from = self.current local params = { from, EventName, to, ... } if self:_call_handler("onbefore" .. EventName, params) == false - or self:_call_handler("onleave" .. from, params) == false then + or self:_call_handler("OnBefore" .. EventName, params) == false + or self:_call_handler("onleave" .. from, params) == false + or self:_call_handler("OnLeave" .. from, params) == false then return false end @@ -11140,14 +11273,16 @@ do -- FSM sub.fsm.fsmparent = self sub.fsm.ReturnEvents = sub.ReturnEvents sub.fsm[sub.StartEvent]( sub.fsm ) - execute = true + execute = false end local fsmparent, Event = self:_isendstate( to ) if fsmparent and Event then self:F2( { "end state: ", fsmparent, Event } ) self:_call_handler("onenter" .. to, params) + self:_call_handler("OnEnter" .. to, params) self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) fsmparent[Event]( fsmparent ) execute = false @@ -11155,25 +11290,16 @@ do -- FSM if execute then -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! - if from ~= to then - self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) + --if from ~= to then self:_call_handler("onenter" .. to, params) - end + self:_call_handler("OnEnter" .. to, params) + --end - self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) - if ( self:_call_handler("OnBefore" .. to, params ) ~= false ) then - - self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) - self:_call_handler("onafter" .. EventName, params) - - self:T3( { On = "OnAfter" .. EventName, callback = self["OnAfter" .. EventName] } ) - ReturnValues = self:_call_handler("OnAfter" .. EventName, params ) - end + self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) end - - return ReturnValues end return nil @@ -11582,7 +11708,7 @@ do -- FSM_SET function FSM_SET:New( FSMSet ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET + self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET if FSMSet then self:Set( FSMSet ) @@ -11652,7 +11778,6 @@ OBJECT = { ObjectName = "", } - --- A DCSObject -- @type DCSObject -- @field id_ The ID of the controllable in DCS @@ -11661,10 +11786,11 @@ OBJECT = { -- @param #OBJECT self -- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name -- @return #OBJECT self -function OBJECT:New( ObjectName ) +function OBJECT:New( ObjectName, Test ) local self = BASE:Inherit( self, BASE:New() ) self:F2( ObjectName ) self.ObjectName = ObjectName + return self end @@ -15446,7 +15572,6 @@ function GROUP:CalculateThreatLevelA2G() end - --- This module contains the UNIT class. -- -- 1) @{#UNIT} class, extends @{Wrapper.Controllable#CONTROLLABLE} @@ -18266,6 +18391,7 @@ SPAWN = { SpawnAliasPrefix = nil, } + --- @type SPAWN.SpawnZoneTable -- @list SpawnZone @@ -21673,6 +21799,10 @@ function MISSILETRAINER:_EventShot( Event ) else -- TODO: some weapons don't know the target unit... Need to develop a workaround for this. SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) + if ( TrainerWeapon:getTypeName() == "9M311" ) then + SCHEDULER:New( TrainerWeapon, TrainerWeapon.destroy, {}, 2 ) + else + end end end @@ -24052,39 +24182,72 @@ function DETECTION_AREAS:CreateDetectionSets() end ---- This module contains the AI_BALANCER class. +--- SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class. +-- +-- AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an +-- engaging simulation environment, even when there are hardly any players in the mission. +-- +-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) -- -- === -- --- 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} --- =================================================================================== +-- # 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} +-- -- The @{AI.AI_Balancer#AI_BALANCER} class monitors and manages as many AI GROUPS as there are --- CLIENTS in a SET_CLIENT collection not occupied by players. +-- CLIENTS in a SET_CLIENT collection not occupied by human players. +-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI. +-- -- The AI_BALANCER class manages internally a collection of AI management objects, which govern the behaviour --- of the underlying AI GROUPS. +-- of the spawned AI @{Wrapper.Group#GROUP)s. -- -- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM) -- and calls for each event the state transition methods providing the internal @{Core.Fsm#FSM_SET.Set} object containing the --- SET_GROUP and additional event parameters provided during the event. +-- AI and additional event parameters provided during the event. -- --- 1.1) AI_BALANCER construction method --- --------------------------------------- --- Create a new AI_BALANCER object with the @{#AI_BALANCER.New} method: +-- ## 1.1) AI_BALANCER construction -- --- * @{#AI_BALANCER.New}: Creates a new AI_BALANCER object. +-- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: +-- +-- ## 1.2) AI_BALANCER is a FSM +-- +-- The AI_BALANCER is a state machine: it manages the different events and states of the @{Core.Fsm#FSM_SET.Set} it is governing. +-- The AI_BALANCER has a default flow to manage the set. +-- +-- ![Process](..\Presentations\AI_Balancer\Dia2.JPG) +-- +-- +-- ### 1.2.1) AI_BALANCER States +-- +-- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. +-- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. +-- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. +-- +-- ### 1.2.2) AI_BALANCER Events +-- +-- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. +-- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. +-- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. -- --- 1.2) --- ---- --- * Add --- * Remove +-- ## 1.3) AI_BALANCER spawn interval for replacement AI -- --- 1.2) AI_BALANCER returns AI to Airbases --- ------------------------------------------ --- You can configure to have the AI to return to: +-- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. -- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. --- -- +-- ## 1.4) AI_BALANCER returns AI to Airbases +-- +-- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. +-- However, there are 2 additional options that you can use to customize the destroy behaviour. +-- When a human player joins a slot, you can configure to let the AI return to: +-- +-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. +-- +-- Note that when AI returns to an airbase, it will trigger the **Return** event and will return, +-- otherwise when the AI is destroyed, the **Destroy** event will be triggered. +-- -- === -- -- **API CHANGE HISTORY** @@ -24097,29 +24260,21 @@ end -- -- Hereby the change log: -- --- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. -- -- === -- --- AUTHORS and CONTRIBUTIONS --- ========================= +-- # **AUTHORS and CONTRIBUTIONS** -- -- ### Contributions: -- --- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. --- Working together with James has resulted in the creation of the AI_BALANCER class. --- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) -- --- * **SNAFU**: --- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. --- None of the script code has been used however within the new AI_BALANCER moose class. +-- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. -- -- ### Authors: -- --- * FlightControl: Framework Design & Programming +-- * FlightControl: Framework Design & Programming and Documentation. -- -- @module AI_Balancer @@ -24128,47 +24283,64 @@ end --- AI_BALANCER class -- @type AI_BALANCER -- @field Core.Set#SET_CLIENT SetClient +-- @field Functional.Spawn#SPAWN SpawnAI +-- @field Wrapper.Group#GROUP Test -- @extends Core.Fsm#FSM_SET AI_BALANCER = { ClassName = "AI_BALANCER", PatrolZones = {}, AIGroups = {}, + Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. + Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. } + + --- Creates a new AI_BALANCER object -- @param #AI_BALANCER self -- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). -- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. -- @return #AI_BALANCER --- @usage --- -- Define a new AI_BALANCER Object. function AI_BALANCER:New( SetClient, SpawnAI ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- Core.Fsm#FSM_SET + local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER self:SetStartState( "None" ) - self:AddTransition( "*", "Start", "Monitoring" ) self:AddTransition( "*", "Monitor", "Monitoring" ) self:AddTransition( "*", "Spawn", "Spawning" ) self:AddTransition( "Spawning", "Spawned", "Spawned" ) self:AddTransition( "*", "Destroy", "Destroying" ) self:AddTransition( "*", "Return", "Returning" ) - self:AddTransition( "*", "End", "End" ) - self:AddTransition( "*", "Dead", "End" ) - - self.SetClient = SetClient + self.SetClient:FilterOnce() self.SpawnAI = SpawnAI + + self.SpawnQueue = {} + self.ToNearestAirbase = false self.ToHomeAirbase = false - self:__Start( 1 ) + self:__Monitor( 1 ) return self end +--- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. +-- Provide 2 identical seconds if the interval should be a fixed amount of seconds. +-- @param #AI_BALANCER self +-- @param #number Earliest The earliest a new AI can be spawned in seconds. +-- @param #number Latest The latest a new AI can be spawned in seconds. +-- @return self +function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) + + self.Earliest = Earliest + self.Latest = Latest + + return self +end + --- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self -- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. @@ -24196,23 +24368,27 @@ end function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) -- OK, Spawn a new group from the default SpawnAI object provided. - local AIGroup = self.SpawnAI:Spawn() + local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP AIGroup:E( "Spawning new AIGroup" ) --TODO: need to rework UnitName thing ... SetGroup:Add( ClientName, AIGroup ) + self.SpawnQueue[ClientName] = nil -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) + self:Spawned( AIGroup ) end --- @param #AI_BALANCER self -- @param Core.Set#SET_GROUP SetGroup -- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, AIGroup ) +function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) AIGroup:Destroy() + SetGroup:Flush() + SetGroup:Remove( ClientName ) + SetGroup:Flush() end --- @param #AI_BALANCER self @@ -24244,18 +24420,22 @@ end --- @param #AI_BALANCER self function AI_BALANCER:onenterMonitoring( SetGroup ) + self:E( { self.SetClient:Count() } ) + self.SetClient:Flush() + self.SetClient:ForEachClient( --- @param Wrapper.Client#CLIENT Client function( Client ) self:E(Client.ClientName) local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP + self:E({Client:IsAlive()}) if Client:IsAlive() then if AIGroup and AIGroup:IsAlive() == true then if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - self:Destroy( AIGroup ) + self:Destroy( Client.UnitName, AIGroup ) else -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. -- If there is a CLIENT, the AI stays engaged and will not return. @@ -24294,9 +24474,13 @@ function AI_BALANCER:onenterMonitoring( SetGroup ) end else if not AIGroup or not AIGroup:IsAlive() == true then - self:E("client not alive") - self:Spawn( Client.UnitName ) - self:E("text after spawn") + self:E( "Client " .. Client.UnitName .. " not alive." ) + if not self.SpawnQueue[Client.UnitName] then + -- Spawn a new AI taking into account the spawn interval Earliest, Latest + self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) + self.SpawnQueue[Client.UnitName] = true + self:E( "New AI Spawned for Client " .. Client.UnitName ) + end end end return true @@ -24730,14 +24914,14 @@ end -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. -- There are 2 moments when state transition methods will be called by the state machine: -- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- * **Leaving** the state. +-- The state transition method needs to start with the name **OnLeave + the name of the state**. -- If the state transition method returns false, then the processing of the state transition will not be done! -- If you want to change the behaviour of the AIControllable at this event, return false, -- but then you'll need to specify your own logic using the AIControllable! -- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- * **Entering** the state. +-- The state transition method needs to start with the name **OnEnter + the name of the state**. -- These state transition methods need to provide a return value, which is specified at the function description. -- -- 2) #AI_CARGO_UNIT class @@ -24823,45 +25007,45 @@ end -- UnLoaded ---- @function [parent=#AI_CARGO] OnBeforeUnLoaded +--- @function [parent=#AI_CARGO] OnLeaveUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnLoaded +--- @function [parent=#AI_CARGO] OnEnterUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Loaded ---- @function [parent=#AI_CARGO] OnBeforeLoaded +--- @function [parent=#AI_CARGO] OnLeaveLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterLoaded +--- @function [parent=#AI_CARGO] OnEnterLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Boarding ---- @function [parent=#AI_CARGO] OnBeforeBoarding +--- @function [parent=#AI_CARGO] OnLeaveBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterBoarding +--- @function [parent=#AI_CARGO] OnEnterBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- UnBoarding ---- @function [parent=#AI_CARGO] OnBeforeUnBoarding +--- @function [parent=#AI_CARGO] OnLeaveUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnBoarding +--- @function [parent=#AI_CARGO] OnEnterUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 98d6002bc..e91c2183c 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170105_0841' ) +env.info( 'Moose Generation Timestamp: 20170108_2104' ) local base = _G Include = {} @@ -3884,7 +3884,11 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume self:F2( { Start, Repeat, RandomizeFactor, Stop } ) self:T3( { SchedulerArguments } ) - + local ObjectName = "-" + if SchedulerObject and SchedulerObject.ClassName and SchedulerObject.ClassID then + ObjectName = SchedulerObject.ClassName .. SchedulerObject.ClassID + end + self:E( { "Schedule :", ObjectName, tostring( SchedulerObject ), Start, Repeat, RandomizeFactor, Stop } ) self.SchedulerObject = SchedulerObject local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( @@ -4013,14 +4017,14 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr if Scheduler.SchedulerObject then self.ObjectSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.ObjectSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), SchedulerObject = tostring(Scheduler.SchedulerObject) } ) else self.PersistentSchedulers[self.CallID] = Scheduler - self:T3( { self.CallID, self.PersistentSchedulers[self.CallID] } ) + self:E( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } ) end self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) - self.Schedule[Scheduler] = {} + self.Schedule[Scheduler] = self.Schedule[Scheduler] or {} self.Schedule[Scheduler][self.CallID] = {} self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments @@ -7667,6 +7671,7 @@ end -- @field #table Filter -- @field #table Set -- @field #table List +-- @field Core.Scheduler#SCHEDULER CallScheduler -- @extends Core.Base#BASE SET_BASE = { ClassName = "SET_BASE", @@ -7684,7 +7689,7 @@ SET_BASE = { function SET_BASE:New( Database ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, BASE:New() ) -- Core.Set#SET_BASE self.Database = Database @@ -7694,6 +7699,8 @@ function SET_BASE:New( Database ) self.List = {} self.List.__index = self.List self.List = setmetatable( { Count = 0 }, self.List ) + + self.CallScheduler = SCHEDULER:New( self ) return self end @@ -8081,7 +8088,7 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen return false end - local Scheduler = SCHEDULER:New( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) + self.CallScheduler:Schedule( self, Schedule, {}, self.TimeInterval, self.TimeInterval, 0 ) return self end @@ -10699,50 +10706,85 @@ end ----- The _MessageQueue object is created when the MESSAGE class module is loaded. ----_MessageQueue = MESSAGEQUEUE:New( 0.5 ) -- ---- This module contains the FSM class and derived FSM_ classes. +--- This module contains the **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes. +-- ## Finite State Machines (FSM) are design patterns allowing efficient (long-lasting) processes and workflows. +-- +-- ![Banner Image](..\Presentations\FSM\Dia1.JPG) +-- +-- A FSM can only be in one of a finite number of states. +-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**. +-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**. +-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**. +-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions. +-- +-- The FSM class supports a **hierarchical implementation of a Finite State Machine**, +-- that is, it allows to **embed existing FSM implementations in a master FSM**. +-- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes. +-- +-- ![Workflow Example](..\Presentations\FSM\Dia2.JPG) +-- +-- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone, +-- orders him to destroy x targets and account the results. +-- Other examples of ready made FSM could be: +-- +-- * route a plane to a zone flown by a human +-- * detect targets by an AI and report to humans +-- * account for destroyed targets by human players +-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle +-- * let an AI patrol a zone +-- +-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes, +-- because **the goal of MOOSE is to simplify mission design complexity for mission building**. +-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes. +-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used, +-- and tailored** by mission designers through **the implementation of Transition Handlers**. +-- Each of these FSM implementation classes start either with: +-- +-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class. +-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class. +-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class. +-- +-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections. +-- +-- ##__Dislaimer:__ +-- The FSM class development is based on a finite state machine implementation made by Conroy Kyle. +-- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine) +-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator. +-- Additionally, I've added extendability and created an API that allows seamless FSM implementation. -- --- This development is based on a state machine implementation made by Conroy Kyle. --- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine --- --- I've taken the development and enhanced it (actually rewrote it) to make the state machine hierarchical... --- It is a fantastic development, this module. --- -- === -- --- ![Banner Image](..\Presentations\FSM\Dia1.jpg) --- -- # 1) @{Core.Fsm#FSM} class, extends @{Core.Base#BASE} -- --- A Finite State Machine (FSM) defines the rules of transitioning between various States triggered by Events. +-- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG) -- --- * A **State** defines a moment in the process. --- * An **Event** describes an action, that can be triggered both internally as externally in the FSM. +-- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines. +-- The derived FSM\_ classes extend the Finite State Machine functionality to run a workflow process for a specific purpose or component. -- --- ## 1.1) Event Handling +-- Finite State Machines have **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- --- ![Event Handlers](..\Presentations\FSM\Dia3.jpg) +-- The **Transition Rules** define the "Process Flow Boundaries", that is, +-- the path that can be followed hopping from state to state upon triggered events. +-- If an event is triggered, and there is no valid path found for that event, +-- an error will be raised and the FSM will stop functioning. -- --- An FSM transitions in **4 moments** when an Event is being handled. --- Each moment can be catched by handling methods defined by the mission designer, --- that will be called by the FSM while executing the transition. --- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be fired. --- --- * To handle **State** moments, create methods starting with OnLeave or OnEnter concatenated with the State name. --- * To handle **Event** moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. +-- The **Transition Handlers** are special methods that can be defined by the mission designer, following a defined syntax. +-- If the FSM object finds a method of such a handler, then the method will be called by the FSM, passing specific parameters. +-- The method can then define its own custom logic to implement the FSM workflow, and to conduct other actions. -- --- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition.** +-- The **Event Triggers** are methods that are defined by the FSM, which the mission designer can use to implement the workflow. +-- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine. -- --- ## 1.2) Event Triggers +-- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation. +-- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**. -- --- ![Event Triggers](..\Presentations\FSM\Dia4.jpg) +-- ## 1.1) FSM Linear Transitions -- --- The FSM creates for each Event **two Event Trigger methods**. --- There are two modes how Events can be triggered, which is **embedded** and **delayed**: +-- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**. +-- The Lineair transition rule evaluation will always be done from the **current state** of the FSM. +-- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop. -- --- * The method **FSM:Event()** triggers an Event that will be processed **embedded** or **immediately**. --- * The method **FSM:__Event( seconds )** triggers an Event that will be processed **delayed** over time, waiting x seconds. --- --- ## 1.3) FSM Transition Rules +-- ### 1.1.1) FSM Transition Rules -- -- The FSM has transition rules that it follows and validates, as it walks the process. -- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event. @@ -10751,12 +10793,107 @@ end -- -- The initial state can be defined using the method @{#FSM.SetStartState}(). The default start state of an FSM is "None". -- --- ### Example +-- Find below an example of a Linear Transition Rule definition for an FSM. -- --- This example creates a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to Green. --- 2 Transition Rules are created, where upon the event Switch, --- the FsmDemo will transition from state Green to Red and vise versa. +-- local Fsm3Switch = FSM:New() -- #FsmDemo +-- FsmSwitch:SetStartState( "Off" ) +-- FsmSwitch:AddTransition( "Off", "SwitchOn", "On" ) +-- FsmSwitch:AddTransition( "Off", "SwitchMiddle", "Middle" ) +-- FsmSwitch:AddTransition( "On", "SwitchOff", "Off" ) +-- FsmSwitch:AddTransition( "Middle", "SwitchOff", "Off" ) +-- +-- The above code snippet models a 3-way switch Linear Transition: +-- +-- * It can be switched **On** by triggering event **SwitchOn**. +-- * It can be switched to the **Middle** position, by triggering event **SwitchMiddle**. +-- * It can be switched **Off** by triggering event **SwitchOff**. +-- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**. +-- +-- ### Some additional comments: +-- +-- Note that Linear Transition Rules **can be declared in a few variations**: +-- +-- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**. +-- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM. +-- +-- The below code snippet shows how the two last lines can be rewritten and consensed. +-- +-- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" ) +-- +-- ### 1.1.2) Transition Handling +-- +-- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG) +-- +-- An FSM transitions in **4 moments** when an Event is being triggered and processed. +-- The mission designer can define for each moment specific logic within methods implementations following a defined API syntax. +-- These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be triggered. +-- +-- * To handle **State** transition moments, create methods starting with OnLeave or OnEnter concatenated with the State name. +-- * To handle **Event** transition moments, create methods starting with OnBefore or OnAfter concatenated with the Event name. +-- +-- **The OnLeave and OnBefore transition methods may return false, which will cancel the transition!** +-- +-- Transition Handler methods need to follow the above specified naming convention, but are also passed parameters from the FSM. +-- These parameters are on the correct order: From, Event, To: +-- +-- * From = A string containing the From state. +-- * Event = A string containing the Event name that was triggered. +-- * To = A string containing the To state. +-- +-- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers). +-- +-- ### 1.1.3) Event Triggers +-- +-- ![Event Triggers](..\Presentations\FSM\Dia5.JPG) +-- +-- The FSM creates for each Event two **Event Trigger methods**. +-- There are two modes how Events can be triggered, which is **synchronous** and **asynchronous**: +-- +-- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**. +-- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__. +-- +-- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time. +-- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact. +-- +-- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering. +-- +-- function FSM:OnAfterEvent( From, Event, To, Amount ) +-- self:E( { Amount = Amount } ) +-- end +-- +-- local Amount = 1 +-- FSM:__Event( 5, Amount ) +-- +-- Amount = Amount + 1 +-- FSM:Event( Text, Amount ) +-- +-- In this example, the **:OnAfterEvent**() Transition Handler implementation will get called when **Event** is being triggered. +-- Before we go into more detail, let's look at the last 4 lines of the example. +-- The last line triggers synchronously the **Event**, and passes Amount as a parameter. +-- The 3rd last line of the example triggers asynchronously **Event**. +-- Event will be processed after 5 seconds, and Amount is given as a parameter. +-- +-- The output of this little code fragment will be: +-- +-- * Amount = 2 +-- * Amount = 2 +-- +-- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing! +-- +-- ### 1.1.4) Linear Transition Example +-- +-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) +-- +-- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare. +-- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build. +-- Have a look at the source code. The source code is also further explained below in this section. +-- +-- The example creates a new FsmDemo object from class FSM. +-- It will set the start state of FsmDemo to state **Green**. +-- Two Linear Transition Rules are created, where upon the event **Switch**, +-- the FsmDemo will transition from state **Green** to **Red** and from **Red** back to **Green**. +-- +-- ![Transition Example](..\Presentations\FSM\Dia6.JPG) -- -- local FsmDemo = FSM:New() -- #FsmDemo -- FsmDemo:SetStartState( "Green" ) @@ -10766,6 +10903,8 @@ end -- In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. -- The next code implements this through the event handling method **OnAfterSwitch**. -- +-- ![Transition Flow](..\Presentations\FSM\Dia7.JPG) +-- -- function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit ) -- self:E( { From, Event, To, FsmUnit } ) -- @@ -10776,7 +10915,7 @@ end -- FsmUnit:Flare(FLARECOLOR.Red) -- end -- end --- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. +-- self:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. -- end -- -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds. @@ -10806,20 +10945,9 @@ end -- -- FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds. -- --- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua) --- --- ### Some additional comments: --- --- Note that transition rules can be declared with a few variations: --- --- * The From states can be a table of strings, indicating that the transition rule will be valid if the current state of the FSM will be one of the given From states. --- * The From state can be a "*", indicating that the transition rule will always be valid, regardless of the current state of the FSM. --- --- This transition will create a new FsmDemo object from class FSM. --- It will set the start state of FsmDemo to Green. --- A new event is added in addition to the above example. --- The new event Stop will cancel the Switching process. --- So, the transtion for event Stop can be executed if the current state of the FSM is either "Red" or "Green". +-- The below code fragment extends the FsmDemo, demonstrating multiple **From states declared as a table**, adding a **Linear Transition Rule**. +-- The new event **Stop** will cancel the Switching process. +-- The transition for event Stop can be executed if the current state of the FSM is either "Red" or "Green". -- -- local FsmDemo = FSM:New() -- #FsmDemo -- FsmDemo:SetStartState( "Green" ) @@ -10830,15 +10958,20 @@ end -- The transition for event Stop can also be simplified, as any current state of the FSM is valid. -- -- FsmDemo:AddTransition( "*", "Stop", "Stopped" ) +-- +-- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped. +-- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt. -- --- ## 1.4) FSM Process Rules +-- ## 1.5) FSM Hierarchical Transitions -- --- The FSM can implement sub-processes that will execute and return multiple possible states. --- Depending upon which state is returned, the main FSM can continue tiggering different events. +-- Hierarchical Transitions allow to re-use readily available and implemented FSMs. +-- This becomes in very useful for mission building, where mission designers build complex processes and workflows, +-- combining smaller FSMs to one single FSM. -- --- The method @{#FSM.AddProcess}() adds a new Sub-Process FSM to the FSM. --- A Sub-Process will start the Sub-Process of the FSM upon the defined triggered Event, --- with multiple possible States as a result. +-- The FSM can embed **Sub-FSMs** that will execute and return **multiple possible Return (End) States**. +-- Depending upon **which state is returned**, the main FSM can continue the flow **triggering specific events**. +-- +-- The method @{#FSM.AddProcess}() adds a new Sub-FSM to the FSM. -- -- ==== -- @@ -10862,11 +10995,11 @@ end -- -- ### Contributions: -- --- * None. +-- * [**Pikey**](https://forums.eagle.ru/member.php?u=62835): Review of documentation & advice for improvements. -- -- ### Authors: -- --- * **FlightControl**: Design & Programming +-- * [**FlightControl**](https://forums.eagle.ru/member.php?u=89536): Design & Programming & documentation. -- -- @module Fsm @@ -10885,7 +11018,7 @@ do -- FSM function FSM:New( FsmT ) -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) + self = BASE:Inherit( self, BASE:New() ) self.options = options or {} self.options.subs = self.options.subs or {} @@ -11112,17 +11245,17 @@ do -- FSM self:E( { EventName, ... } ) - local can, to = self:can( EventName ) - self:E( { EventName, self.current, can, to } ) + local Can, to = self:can( EventName ) + self:E( { From = self.current, Event = EventName, To = to, Can = Can } ) - local ReturnValues = nil - - if can then + if Can then local from = self.current local params = { from, EventName, to, ... } if self:_call_handler("onbefore" .. EventName, params) == false - or self:_call_handler("onleave" .. from, params) == false then + or self:_call_handler("OnBefore" .. EventName, params) == false + or self:_call_handler("onleave" .. from, params) == false + or self:_call_handler("OnLeave" .. from, params) == false then return false end @@ -11140,14 +11273,16 @@ do -- FSM sub.fsm.fsmparent = self sub.fsm.ReturnEvents = sub.ReturnEvents sub.fsm[sub.StartEvent]( sub.fsm ) - execute = true + execute = false end local fsmparent, Event = self:_isendstate( to ) if fsmparent and Event then self:F2( { "end state: ", fsmparent, Event } ) self:_call_handler("onenter" .. to, params) + self:_call_handler("OnEnter" .. to, params) self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) fsmparent[Event]( fsmparent ) execute = false @@ -11155,25 +11290,16 @@ do -- FSM if execute then -- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute! - if from ~= to then - self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) + --if from ~= to then self:_call_handler("onenter" .. to, params) - end + self:_call_handler("OnEnter" .. to, params) + --end - self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) - if ( self:_call_handler("OnBefore" .. to, params ) ~= false ) then - - self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) - self:_call_handler("onafter" .. EventName, params) - - self:T3( { On = "OnAfter" .. EventName, callback = self["OnAfter" .. EventName] } ) - ReturnValues = self:_call_handler("OnAfter" .. EventName, params ) - end + self:_call_handler("onafter" .. EventName, params) + self:_call_handler("OnAfter" .. EventName, params) self:_call_handler("onstatechange", params) end - - return ReturnValues end return nil @@ -11582,7 +11708,7 @@ do -- FSM_SET function FSM_SET:New( FSMSet ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET + self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_SET if FSMSet then self:Set( FSMSet ) @@ -11652,7 +11778,6 @@ OBJECT = { ObjectName = "", } - --- A DCSObject -- @type DCSObject -- @field id_ The ID of the controllable in DCS @@ -11661,10 +11786,11 @@ OBJECT = { -- @param #OBJECT self -- @param Dcs.DCSWrapper.Object#Object ObjectName The Object name -- @return #OBJECT self -function OBJECT:New( ObjectName ) +function OBJECT:New( ObjectName, Test ) local self = BASE:Inherit( self, BASE:New() ) self:F2( ObjectName ) self.ObjectName = ObjectName + return self end @@ -15446,7 +15572,6 @@ function GROUP:CalculateThreatLevelA2G() end - --- This module contains the UNIT class. -- -- 1) @{#UNIT} class, extends @{Wrapper.Controllable#CONTROLLABLE} @@ -18266,6 +18391,7 @@ SPAWN = { SpawnAliasPrefix = nil, } + --- @type SPAWN.SpawnZoneTable -- @list SpawnZone @@ -24056,39 +24182,72 @@ function DETECTION_AREAS:CreateDetectionSets() end ---- This module contains the AI_BALANCER class. +--- SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class. +-- +-- AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an +-- engaging simulation environment, even when there are hardly any players in the mission. +-- +-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG) -- -- === -- --- 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} --- =================================================================================== +-- # 1) @{AI.AI_Balancer#AI_BALANCER} class, extends @{Core.Fsm#FSM_SET} +-- -- The @{AI.AI_Balancer#AI_BALANCER} class monitors and manages as many AI GROUPS as there are --- CLIENTS in a SET_CLIENT collection not occupied by players. +-- CLIENTS in a SET_CLIENT collection not occupied by human players. +-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI. +-- -- The AI_BALANCER class manages internally a collection of AI management objects, which govern the behaviour --- of the underlying AI GROUPS. +-- of the spawned AI @{Wrapper.Group#GROUP)s. -- -- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM) -- and calls for each event the state transition methods providing the internal @{Core.Fsm#FSM_SET.Set} object containing the --- SET_GROUP and additional event parameters provided during the event. +-- AI and additional event parameters provided during the event. -- --- 1.1) AI_BALANCER construction method --- --------------------------------------- --- Create a new AI_BALANCER object with the @{#AI_BALANCER.New} method: +-- ## 1.1) AI_BALANCER construction -- --- * @{#AI_BALANCER.New}: Creates a new AI_BALANCER object. +-- Create a new AI_BALANCER object with the @{#AI_BALANCER.New}() method: +-- +-- ## 1.2) AI_BALANCER is a FSM +-- +-- The AI_BALANCER is a state machine: it manages the different events and states of the @{Core.Fsm#FSM_SET.Set} it is governing. +-- The AI_BALANCER has a default flow to manage the set. +-- +-- ![Process](..\Presentations\AI_Balancer\Dia2.JPG) +-- +-- +-- ### 1.2.1) AI_BALANCER States +-- +-- * **Monitoring** ( Set ): Monitoring the Set if all AI is spawned for the Clients. +-- * **Spawning** ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroying** ( Set, AIGroup ): The AI is being destroyed. +-- * **Returning** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any. +-- +-- ### 1.2.2) AI_BALANCER Events +-- +-- * **Monitor** ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set. +-- * **Spawn** ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference. +-- * **Spawned** ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes. +-- * **Destroy** ( Set, AIGroup ): The AI is being destroyed. +-- * **Return** ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. -- --- 1.2) --- ---- --- * Add --- * Remove +-- ## 1.3) AI_BALANCER spawn interval for replacement AI -- --- 1.2) AI_BALANCER returns AI to Airbases --- ------------------------------------------ --- You can configure to have the AI to return to: +-- Use the method @{#AI_BALANCER.InitSpawnInterval}() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned. -- --- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Wrapper.Airbase#AIRBASE}. --- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. --- -- +-- ## 1.4) AI_BALANCER returns AI to Airbases +-- +-- By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. +-- However, there are 2 additional options that you can use to customize the destroy behaviour. +-- When a human player joins a slot, you can configure to let the AI return to: +-- +-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}. +-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}. +-- +-- Note that when AI returns to an airbase, it will trigger the **Return** event and will return, +-- otherwise when the AI is destroyed, the **Destroy** event will be triggered. +-- -- === -- -- **API CHANGE HISTORY** @@ -24101,29 +24260,21 @@ end -- -- Hereby the change log: -- --- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- 2017-01-08: AI_BALANCER:**InitSpawnInterval( Earliest, Latest )** added. -- -- === -- --- AUTHORS and CONTRIBUTIONS --- ========================= +-- # **AUTHORS and CONTRIBUTIONS** -- -- ### Contributions: -- --- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. --- Working together with James has resulted in the creation of the AI_BALANCER class. --- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) -- --- * **SNAFU**: --- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. --- None of the script code has been used however within the new AI_BALANCER moose class. +-- * **SNAFU**: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class. -- -- ### Authors: -- --- * FlightControl: Framework Design & Programming +-- * FlightControl: Framework Design & Programming and Documentation. -- -- @module AI_Balancer @@ -24132,47 +24283,64 @@ end --- AI_BALANCER class -- @type AI_BALANCER -- @field Core.Set#SET_CLIENT SetClient +-- @field Functional.Spawn#SPAWN SpawnAI +-- @field Wrapper.Group#GROUP Test -- @extends Core.Fsm#FSM_SET AI_BALANCER = { ClassName = "AI_BALANCER", PatrolZones = {}, AIGroups = {}, + Earliest = 5, -- Earliest a new AI can be spawned is in 5 seconds. + Latest = 60, -- Latest a new AI can be spawned is in 60 seconds. } + + --- Creates a new AI_BALANCER object -- @param #AI_BALANCER self -- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). -- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. -- @return #AI_BALANCER --- @usage --- -- Define a new AI_BALANCER Object. function AI_BALANCER:New( SetClient, SpawnAI ) -- Inherits from BASE - local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- Core.Fsm#FSM_SET + local self = BASE:Inherit( self, FSM_SET:New( SET_GROUP:New() ) ) -- AI.AI_Balancer#AI_BALANCER self:SetStartState( "None" ) - self:AddTransition( "*", "Start", "Monitoring" ) self:AddTransition( "*", "Monitor", "Monitoring" ) self:AddTransition( "*", "Spawn", "Spawning" ) self:AddTransition( "Spawning", "Spawned", "Spawned" ) self:AddTransition( "*", "Destroy", "Destroying" ) self:AddTransition( "*", "Return", "Returning" ) - self:AddTransition( "*", "End", "End" ) - self:AddTransition( "*", "Dead", "End" ) - - self.SetClient = SetClient + self.SetClient:FilterOnce() self.SpawnAI = SpawnAI + + self.SpawnQueue = {} + self.ToNearestAirbase = false self.ToHomeAirbase = false - self:__Start( 1 ) + self:__Monitor( 1 ) return self end +--- Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI. +-- Provide 2 identical seconds if the interval should be a fixed amount of seconds. +-- @param #AI_BALANCER self +-- @param #number Earliest The earliest a new AI can be spawned in seconds. +-- @param #number Latest The latest a new AI can be spawned in seconds. +-- @return self +function AI_BALANCER:InitSpawnInterval( Earliest, Latest ) + + self.Earliest = Earliest + self.Latest = Latest + + return self +end + --- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}. -- @param #AI_BALANCER self -- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}. @@ -24200,23 +24368,27 @@ end function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName ) -- OK, Spawn a new group from the default SpawnAI object provided. - local AIGroup = self.SpawnAI:Spawn() + local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP AIGroup:E( "Spawning new AIGroup" ) --TODO: need to rework UnitName thing ... SetGroup:Add( ClientName, AIGroup ) + self.SpawnQueue[ClientName] = nil -- Fire the Spawned event. The first parameter is the AIGroup just Spawned. -- Mission designers can catch this event to bind further actions to the AIGroup. - self:Spawned( AIGroup ) + self:Spawned( AIGroup ) end --- @param #AI_BALANCER self -- @param Core.Set#SET_GROUP SetGroup -- @param Wrapper.Group#GROUP AIGroup -function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, AIGroup ) +function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) AIGroup:Destroy() + SetGroup:Flush() + SetGroup:Remove( ClientName ) + SetGroup:Flush() end --- @param #AI_BALANCER self @@ -24248,18 +24420,22 @@ end --- @param #AI_BALANCER self function AI_BALANCER:onenterMonitoring( SetGroup ) + self:E( { self.SetClient:Count() } ) + self.SetClient:Flush() + self.SetClient:ForEachClient( --- @param Wrapper.Client#CLIENT Client function( Client ) self:E(Client.ClientName) local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP + self:E({Client:IsAlive()}) if Client:IsAlive() then if AIGroup and AIGroup:IsAlive() == true then if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - self:Destroy( AIGroup ) + self:Destroy( Client.UnitName, AIGroup ) else -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. -- If there is a CLIENT, the AI stays engaged and will not return. @@ -24298,9 +24474,13 @@ function AI_BALANCER:onenterMonitoring( SetGroup ) end else if not AIGroup or not AIGroup:IsAlive() == true then - self:E("client not alive") - self:Spawn( Client.UnitName ) - self:E("text after spawn") + self:E( "Client " .. Client.UnitName .. " not alive." ) + if not self.SpawnQueue[Client.UnitName] then + -- Spawn a new AI taking into account the spawn interval Earliest, Latest + self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName ) + self.SpawnQueue[Client.UnitName] = true + self:E( "New AI Spawned for Client " .. Client.UnitName ) + end end end return true @@ -24734,14 +24914,14 @@ end -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. -- There are 2 moments when state transition methods will be called by the state machine: -- --- * **Before** the state transition. --- The state transition method needs to start with the name **OnBefore + the name of the state**. +-- * **Leaving** the state. +-- The state transition method needs to start with the name **OnLeave + the name of the state**. -- If the state transition method returns false, then the processing of the state transition will not be done! -- If you want to change the behaviour of the AIControllable at this event, return false, -- but then you'll need to specify your own logic using the AIControllable! -- --- * **After** the state transition. --- The state transition method needs to start with the name **OnAfter + the name of the state**. +-- * **Entering** the state. +-- The state transition method needs to start with the name **OnEnter + the name of the state**. -- These state transition methods need to provide a return value, which is specified at the function description. -- -- 2) #AI_CARGO_UNIT class @@ -24827,45 +25007,45 @@ end -- UnLoaded ---- @function [parent=#AI_CARGO] OnBeforeUnLoaded +--- @function [parent=#AI_CARGO] OnLeaveUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnLoaded +--- @function [parent=#AI_CARGO] OnEnterUnLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Loaded ---- @function [parent=#AI_CARGO] OnBeforeLoaded +--- @function [parent=#AI_CARGO] OnLeaveLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterLoaded +--- @function [parent=#AI_CARGO] OnEnterLoaded -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- Boarding ---- @function [parent=#AI_CARGO] OnBeforeBoarding +--- @function [parent=#AI_CARGO] OnLeaveBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterBoarding +--- @function [parent=#AI_CARGO] OnEnterBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- UnBoarding ---- @function [parent=#AI_CARGO] OnBeforeUnBoarding +--- @function [parent=#AI_CARGO] OnLeaveUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable -- @return #boolean ---- @function [parent=#AI_CARGO] OnAfterUnBoarding +--- @function [parent=#AI_CARGO] OnEnterUnBoarding -- @param #AI_CARGO self -- @param Wrapper.Controllable#CONTROLLABLE Controllable diff --git a/Moose Test Missions/ABP - Airbase Police/APL-001 - Caucasus/APL-001 - Caucasus.miz b/Moose Test Missions/ABP - Airbase Police/APL-001 - Caucasus/APL-001 - Caucasus.miz index 538b163e9..7414f49ac 100644 Binary files a/Moose Test Missions/ABP - Airbase Police/APL-001 - Caucasus/APL-001 - Caucasus.miz and b/Moose Test Missions/ABP - Airbase Police/APL-001 - Caucasus/APL-001 - Caucasus.miz differ diff --git a/Moose Test Missions/ABP - Airbase Police/APL-002 - Nevada/APL-002 - Nevada.miz b/Moose Test Missions/ABP - Airbase Police/APL-002 - Nevada/APL-002 - Nevada.miz index 317d23ea6..11c7ad122 100644 Binary files a/Moose Test Missions/ABP - Airbase Police/APL-002 - Nevada/APL-002 - Nevada.miz and b/Moose Test Missions/ABP - Airbase Police/APL-002 - Nevada/APL-002 - Nevada.miz differ diff --git a/Moose Test Missions/ACL - Airbase Cleaner/ACL-001 - Airbase CleanUp/ACL-001 - Airbase CleanUp.miz b/Moose Test Missions/ACL - Airbase Cleaner/ACL-001 - Airbase CleanUp/ACL-001 - Airbase CleanUp.miz index dc6469d77..7d0d83a20 100644 Binary files a/Moose Test Missions/ACL - Airbase Cleaner/ACL-001 - Airbase CleanUp/ACL-001 - Airbase CleanUp.miz and b/Moose Test Missions/ACL - Airbase Cleaner/ACL-001 - Airbase CleanUp/ACL-001 - Airbase CleanUp.miz differ diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.lua b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.lua index bf9376140..7af0df386 100644 --- a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.lua +++ b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.lua @@ -24,7 +24,7 @@ -- @module TEST.AI_BALANCER.T001 -- Define the SET of CLIENTs from the red coalition. This SET is filled during startup. -local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart() +local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ) -- Define the SPAWN object for the red AI plane template. -- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off. diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.miz b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.miz new file mode 100644 index 000000000..bf327c74e Binary files /dev/null and b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 - Spawned AI.miz differ diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 -Spawned AI.miz b/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 -Spawned AI.miz deleted file mode 100644 index 6b76be0dd..000000000 Binary files a/Moose Test Missions/AIB - AI Balancing/AIB-001 - Spawned AI/AIB-001 -Spawned AI.miz and /dev/null differ diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.lua b/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.lua index a1347dbbe..caae5615d 100644 --- a/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.lua +++ b/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.lua @@ -25,7 +25,7 @@ -- @module TEST.AI_BALANCER.T002 -- Define the SET of CLIENTs from the red coalition. This SET is filled during startup. -local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart() +local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ) -- Define the SPAWN object for the red AI plane template. -- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off. @@ -46,4 +46,4 @@ function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup ) Patrol:SetControllable( AIGroup ) Patrol:__Start( 5 ) -end \ No newline at end of file +end diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz b/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz index ae5c9f127..4fecaea15 100644 Binary files a/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz and b/Moose Test Missions/AIB - AI Balancing/AIB-002 - Patrol AI/AIB-002 - Patrol AI.miz differ diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.lua b/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.lua index ff37d8cdd..a647bedee 100644 --- a/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.lua +++ b/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.lua @@ -1,16 +1,16 @@ +RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ) +RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 ) +RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn ) -local US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterStart() - -local US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 ) -local US_AI_Balancer = AI_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn ) - -local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart() -local RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 ) -local RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn ) - -local RU_AirbasesSet = SET_AIRBASE:New():FilterCoalitions("red"):FilterStart() +RU_AirbasesSet = SET_AIRBASE:New():FilterCoalitions("red"):FilterStart() RU_AirbasesSet:Flush() RU_AI_Balancer:ReturnToNearestAirbases( 10000, RU_AirbasesSet ) + + +US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ) +US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 ) +US_AI_Balancer = AI_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn ) + --RU_AI_Balancer:ReturnToHomeAirbase( 10000 ) --local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Blue" ) diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.miz b/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.miz index 219ba64bc..4cf93ec5a 100644 Binary files a/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.miz and b/Moose Test Missions/AIB - AI Balancing/AIB-003 - Two coalitions InitCleanUp test/AIB-003 - Two coalitions InitCleanUp test.miz differ diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.lua b/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.lua new file mode 100644 index 000000000..f65e27f88 --- /dev/null +++ b/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.lua @@ -0,0 +1,46 @@ +-- Name: Respawn Test when Destroyed +-- Author: FlightControl +-- Date Created: 7 January 2017 +-- +-- # Situation: +-- +-- For the red coalition, 2 client slots are foreseen. +-- For those players that have not joined the mission, red AI is spawned. +-- The red AI should start patrolling an area. +-- +-- The blue side has SAMs nearby. +-- Once the red AI takes off, the red AI is attacked by the blue SAMs. +-- Red AI should be killed and once that happens, a Respawn of the group should happen! +-- The Respawn happens through the InitCleanUp() API of SPAWN. +-- +-- # Test cases: +-- +-- 1. If no player is logging into the red slots, 2 red AI planes should be alive. +-- 2. If a player joins one red slot, one red AI plane should return to the nearest home base. +-- 3. If two players join the red slots, no AI plane should be spawned, and all airborne AI planes should return to the nearest home base. +-- 4. Monitor that once a red AI is destroyed, that it ReSpawns... +-- + +-- Define the SET of CLIENTs from the red coalition. This SET is filled during startup. +local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ) + +-- Define the SPAWN object for the red AI plane template. +-- We use InitCleanUp to check every 20 seconds, if there are no planes blocked at the airbase, waithing for take-off. +-- If a blocked plane exists, this red plane will be ReSpawned. +local RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 ) + +-- Start the AI_BALANCER, using the SET of red CLIENTs, and the SPAWN object as a parameter. +local RU_AI_Balancer = AI_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn ) + +function RU_AI_Balancer:OnAfterSpawned( SetGroup, From, Event, To, AIGroup ) + + local PatrolZoneGroup = GROUP:FindByName( "PatrolZone" ) + local PatrolZone = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) + + + local Patrol = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 400, 600 ) + Patrol:ManageFuel( 0.2, 60 ) + Patrol:SetControllable( AIGroup ) + Patrol:__Start( 5 ) + +end diff --git a/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.miz b/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.miz new file mode 100644 index 000000000..531b89edc Binary files /dev/null and b/Moose Test Missions/AIB - AI Balancing/AIB-004 - Respawn Test when Destroyed/AIB-004 - Respawn Test when Destroyed.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-001 - Unit Boarding/CGO-001 - Unit Boarding.miz b/Moose Test Missions/CGO - Cargo/CGO-001 - Unit Boarding/CGO-001 - Unit Boarding.miz index 703781aff..b29a41798 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-001 - Unit Boarding/CGO-001 - Unit Boarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-001 - Unit Boarding/CGO-001 - Unit Boarding.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-002 - Unit Unboarding/CGO-002 - Unit Unboarding.miz b/Moose Test Missions/CGO - Cargo/CGO-002 - Unit Unboarding/CGO-002 - Unit Unboarding.miz index 8c548daa4..dd560114c 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-002 - Unit Unboarding/CGO-002 - Unit Unboarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-002 - Unit Unboarding/CGO-002 - Unit Unboarding.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.lua b/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.lua index b5eb57036..9d09469bc 100644 --- a/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.lua +++ b/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.lua @@ -12,13 +12,13 @@ local CargoCarrierTo = UNIT:FindByName( "CarrierTo" ) InfantryCargo:Board( CargoCarrierFrom ) -- Once the Cargo has been loaded into the Carrier, drive to a point and unload the Cargo. -function InfantryCargo:OnAfterLoaded() +function InfantryCargo:OnEnterLoaded() self:__UnBoard( 1 ) - self.OnAfterLoaded = nil + self.OnEnterLoaded = nil end -- Once the Cargo has been unloaded from the Carrier (the Cargo has arrived to the unload gathering point), OnBoard the Cargo in the other Carrier. -function InfantryCargo:OnAfterUnLoaded() +function InfantryCargo:OnEnterUnLoaded() self:__Board( 1, CargoCarrierTo ) - self.OnAfterUnLoaded = nil + self.OnEnterUnLoaded = nil end diff --git a/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.miz b/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.miz index d7bae593c..f90283691 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.miz and b/Moose Test Missions/CGO - Cargo/CGO-003 - Unit Transferring/CGO-003 - Unit Transferring.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-101 - Group Boarding/CGO-101 - Group Boarding.miz b/Moose Test Missions/CGO - Cargo/CGO-101 - Group Boarding/CGO-101 - Group Boarding.miz index 6dfbf3998..c8ed2b853 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-101 - Group Boarding/CGO-101 - Group Boarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-101 - Group Boarding/CGO-101 - Group Boarding.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-102 - Group Unboarding/CGO-102 - Group Unboarding.miz b/Moose Test Missions/CGO - Cargo/CGO-102 - Group Unboarding/CGO-102 - Group Unboarding.miz index 4ad60d11d..cead44ff1 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-102 - Group Unboarding/CGO-102 - Group Unboarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-102 - Group Unboarding/CGO-102 - Group Unboarding.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.lua b/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.lua index 06968a6da..4b1d85f18 100644 --- a/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.lua +++ b/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.lua @@ -17,13 +17,13 @@ local CargoCarrierTo = UNIT:FindByName( "CarrierTo" ) InfantryCargo:Board( CargoCarrierFrom ) -- Once the Cargo has been loaded into the Carrier, drive to a point and unload the Cargo. -function InfantryCargo:OnAfterLoaded() +function InfantryCargo:OnEnterLoaded() self:__UnBoard( 1 ) - self.OnAfterLoaded = nil + self.OnEnterLoaded = nil end -- Once the Cargo has been unloaded from the Carrier (the Cargo has arrived to the unload gathering point), OnBoard the Cargo in the other Carrier. -function InfantryCargo:OnAfterUnLoaded() +function InfantryCargo:OnEnterUnLoaded() self:__Board( 1, CargoCarrierTo ) - self.OnAfterUnLoaded = nil + self.OnEnterUnLoaded = nil end diff --git a/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.miz b/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.miz index b3d831071..bdc16d837 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.miz and b/Moose Test Missions/CGO - Cargo/CGO-103 - Group Transferring/CGO-103 - Group Transferring.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-201 - Package Boarding/CGO-201 - Package Boarding.miz b/Moose Test Missions/CGO - Cargo/CGO-201 - Package Boarding/CGO-201 - Package Boarding.miz index ab9da98db..8a0f07a9f 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-201 - Package Boarding/CGO-201 - Package Boarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-201 - Package Boarding/CGO-201 - Package Boarding.miz differ diff --git a/Moose Test Missions/CGO - Cargo/CGO-202 - Package Unboarding/CGO-202 - Package Unboarding.miz b/Moose Test Missions/CGO - Cargo/CGO-202 - Package Unboarding/CGO-202 - Package Unboarding.miz index 9cb466c70..25be44252 100644 Binary files a/Moose Test Missions/CGO - Cargo/CGO-202 - Package Unboarding/CGO-202 - Package Unboarding.miz and b/Moose Test Missions/CGO - Cargo/CGO-202 - Package Unboarding/CGO-202 - Package Unboarding.miz differ diff --git a/Moose Test Missions/DET - Detection/DET-001 - Detection Areas/DET-001 - Detection Areas.miz b/Moose Test Missions/DET - Detection/DET-001 - Detection Areas/DET-001 - Detection Areas.miz index dc58789bf..0436d3219 100644 Binary files a/Moose Test Missions/DET - Detection/DET-001 - Detection Areas/DET-001 - Detection Areas.miz and b/Moose Test Missions/DET - Detection/DET-001 - Detection Areas/DET-001 - Detection Areas.miz differ diff --git a/Moose Test Missions/DET - Detection/DET-101 - Detection Reporting/DET-101 - Detection Reporting.miz b/Moose Test Missions/DET - Detection/DET-101 - Detection Reporting/DET-101 - Detection Reporting.miz index ab1c7b2ee..079240400 100644 Binary files a/Moose Test Missions/DET - Detection/DET-101 - Detection Reporting/DET-101 - Detection Reporting.miz and b/Moose Test Missions/DET - Detection/DET-101 - Detection Reporting/DET-101 - Detection Reporting.miz differ diff --git a/Moose Test Missions/ESC - Escorting/ESC-001 - Escorting Helicopters/ESC-001 - Escorting Helicopters.miz b/Moose Test Missions/ESC - Escorting/ESC-001 - Escorting Helicopters/ESC-001 - Escorting Helicopters.miz index 6e77213f5..1ac71d916 100644 Binary files a/Moose Test Missions/ESC - Escorting/ESC-001 - Escorting Helicopters/ESC-001 - Escorting Helicopters.miz and b/Moose Test Missions/ESC - Escorting/ESC-001 - Escorting Helicopters/ESC-001 - Escorting Helicopters.miz differ diff --git a/Moose Test Missions/FSM - Finite State Machine/FSM-100 - Transition Explanation/FSM-100 - Transition Explanation.miz b/Moose Test Missions/FSM - Finite State Machine/FSM-100 - Transition Explanation/FSM-100 - Transition Explanation.miz index 12e14f675..e64629870 100644 Binary files a/Moose Test Missions/FSM - Finite State Machine/FSM-100 - Transition Explanation/FSM-100 - Transition Explanation.miz and b/Moose Test Missions/FSM - Finite State Machine/FSM-100 - Transition Explanation/FSM-100 - Transition Explanation.miz differ diff --git a/Moose Test Missions/GRP - Group Commands/GRP-200 - Follow Group/GRP-200 - Follow Group.miz b/Moose Test Missions/GRP - Group Commands/GRP-200 - Follow Group/GRP-200 - Follow Group.miz index 6dc8223a9..1b10d05cd 100644 Binary files a/Moose Test Missions/GRP - Group Commands/GRP-200 - Follow Group/GRP-200 - Follow Group.miz and b/Moose Test Missions/GRP - Group Commands/GRP-200 - Follow Group/GRP-200 - Follow Group.miz differ diff --git a/Moose Test Missions/GRP - Group Commands/GRP-300 - Switch WayPoints/GRP-300 - Switch WayPoints.miz b/Moose Test Missions/GRP - Group Commands/GRP-300 - Switch WayPoints/GRP-300 - Switch WayPoints.miz index da1651bbc..27601dbb3 100644 Binary files a/Moose Test Missions/GRP - Group Commands/GRP-300 - Switch WayPoints/GRP-300 - Switch WayPoints.miz and b/Moose Test Missions/GRP - Group Commands/GRP-300 - Switch WayPoints/GRP-300 - Switch WayPoints.miz differ diff --git a/Moose Test Missions/GRP - Group Commands/Moose_Test_WRAPPER.miz b/Moose Test Missions/GRP - Group Commands/Moose_Test_WRAPPER.miz index 910d4155e..cba7012ae 100644 Binary files a/Moose Test Missions/GRP - Group Commands/Moose_Test_WRAPPER.miz and b/Moose Test Missions/GRP - Group Commands/Moose_Test_WRAPPER.miz differ diff --git a/Moose Test Missions/MEN - Menu Options/MEN-001 - Menu Client/MEN-001 - Menu Client.miz b/Moose Test Missions/MEN - Menu Options/MEN-001 - Menu Client/MEN-001 - Menu Client.miz index 49f40a33f..9376e6d0b 100644 Binary files a/Moose Test Missions/MEN - Menu Options/MEN-001 - Menu Client/MEN-001 - Menu Client.miz and b/Moose Test Missions/MEN - Menu Options/MEN-001 - Menu Client/MEN-001 - Menu Client.miz differ diff --git a/Moose Test Missions/MEN - Menu Options/MEN-002 - Menu Coalition/MEN-002 - Menu Coalition.miz b/Moose Test Missions/MEN - Menu Options/MEN-002 - Menu Coalition/MEN-002 - Menu Coalition.miz index b915c3d37..18000e8c1 100644 Binary files a/Moose Test Missions/MEN - Menu Options/MEN-002 - Menu Coalition/MEN-002 - Menu Coalition.miz and b/Moose Test Missions/MEN - Menu Options/MEN-002 - Menu Coalition/MEN-002 - Menu Coalition.miz differ diff --git a/Moose Test Missions/MEN - Menu Options/MEN-003 - Menu Group/MEN-003 - Menu Group.miz b/Moose Test Missions/MEN - Menu Options/MEN-003 - Menu Group/MEN-003 - Menu Group.miz index 78d351a39..7fc16d70e 100644 Binary files a/Moose Test Missions/MEN - Menu Options/MEN-003 - Menu Group/MEN-003 - Menu Group.miz and b/Moose Test Missions/MEN - Menu Options/MEN-003 - Menu Group/MEN-003 - Menu Group.miz differ diff --git a/Moose Test Missions/MIT - Missile Trainer/MIT-001 - Missile Trainer/MIT-001 - Missile Trainer.miz b/Moose Test Missions/MIT - Missile Trainer/MIT-001 - Missile Trainer/MIT-001 - Missile Trainer.miz index 47e71638b..fd3375645 100644 Binary files a/Moose Test Missions/MIT - Missile Trainer/MIT-001 - Missile Trainer/MIT-001 - Missile Trainer.miz and b/Moose Test Missions/MIT - Missile Trainer/MIT-001 - Missile Trainer/MIT-001 - Missile Trainer.miz differ diff --git a/Moose Test Missions/MOOSE_Test_Template.miz b/Moose Test Missions/MOOSE_Test_Template.miz index f5d3c1b27..837bed5fd 100644 Binary files a/Moose Test Missions/MOOSE_Test_Template.miz and b/Moose Test Missions/MOOSE_Test_Template.miz differ diff --git a/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.lua b/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.lua index 2c35574c8..5d96265c3 100644 --- a/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.lua +++ b/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.lua @@ -35,7 +35,7 @@ Patrol2:ManageFuel( 0.2, 0 ) -- @param #AI_PATROLZONE self -- @param Wrapper.Group#GROUP AIGroup -- @return #boolean If false is returned, then the OnAfter state transition function will not be called. -function Patrol1:OnBeforeRTB( AIGroup ) +function Patrol1:OnLeaveRTB( AIGroup ) AIGroup:MessageToRed( "Returning to base", 20 ) end @@ -51,14 +51,14 @@ end --- State transition function for the PROCESS\_PATROLZONE **Patrol1** object -- @param Process_PatrolCore.Zone#AI_PATROLZONE self -- @param Wrapper.Group#GROUP AIGroup -function Patrol1:OnAfterPatrol( AIGroup ) +function Patrol1:OnEnterPatrol( AIGroup ) AIGroup:MessageToRed( "Patrolling in zone " .. PatrolZone1:GetName() , 20 ) end --- State transition function for the PROCESS\_PATROLZONE **Patrol2** object -- @param #AI_PATROLZONE self -- @param Wrapper.Group#GROUP AIGroup --- @return #boolean If false is returned, then the OnAfter state transition function will not be called. +-- @return #boolean If false is returned, then the OnEnter state transition function will not be called. function Patrol2:OnBeforeRTB( AIGroup ) AIGroup:MessageToRed( "Returning to base", 20 ) end @@ -66,7 +66,7 @@ end --- State transition function for the PROCESS\_PATROLZONE **Patrol2** object -- @param Process_PatrolCore.Zone#AI_PATROLZONE self -- @param Wrapper.Group#GROUP AIGroup -function Patrol2:OnAfterRTB( AIGroup ) +function Patrol2:OnEnterRTB( AIGroup ) local NewGroup = PatrolSpawn:Spawn() Patrol1:SetControllable( NewGroup ) Patrol1:__Start( 1 ) @@ -75,6 +75,6 @@ end --- State transition function for the PROCESS\_PATROLZONE **Patrol2** object -- @param Process_PatrolCore.Zone#AI_PATROLZONE self -- @param Wrapper.Group#GROUP AIGroup -function Patrol2:OnAfterPatrol( AIGroup ) +function Patrol2:OnEnterPatrol( AIGroup ) AIGroup:MessageToRed( "Patrolling in zone " .. PatrolZone2:GetName() , 20 ) end diff --git a/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.miz b/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.miz index eb6ab97be..67b66ec01 100644 Binary files a/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.miz and b/Moose Test Missions/PAT - Patrolling/PAT-001 - Switching Patrol Zones/PAT-001 - Switching Patrol Zones.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-000 - Simple Scheduling/SCH-000 - Simple Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-000 - Simple Scheduling/SCH-000 - Simple Scheduling.miz index f70f33e03..db671dee2 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-000 - Simple Scheduling/SCH-000 - Simple Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-000 - Simple Scheduling/SCH-000 - Simple Scheduling.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-001 - Simple Object Scheduling/SCH-001 - Simple Object Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-001 - Simple Object Scheduling/SCH-001 - Simple Object Scheduling.miz index b0da5157b..bc5407657 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-001 - Simple Object Scheduling/SCH-001 - Simple Object Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-001 - Simple Object Scheduling/SCH-001 - Simple Object Scheduling.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-100 - Simple Repeat Scheduling/SCH-100 - Simple Repeat Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-100 - Simple Repeat Scheduling/SCH-100 - Simple Repeat Scheduling.miz index ad4d02030..98f22bbce 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-100 - Simple Repeat Scheduling/SCH-100 - Simple Repeat Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-100 - Simple Repeat Scheduling/SCH-100 - Simple Repeat Scheduling.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-110 - Object Repeat Scheduling/SCH-110 - Object Repeat Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-110 - Object Repeat Scheduling/SCH-110 - Object Repeat Scheduling.miz index f25018759..d8cf88d58 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-110 - Object Repeat Scheduling/SCH-110 - Object Repeat Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-110 - Object Repeat Scheduling/SCH-110 - Object Repeat Scheduling.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-200 - Simple Repeat Scheduling Stop and Start/SCH-200 - Simple Repeat Scheduling Stop and Start.miz b/Moose Test Missions/SCH - Scheduler/SCH-200 - Simple Repeat Scheduling Stop and Start/SCH-200 - Simple Repeat Scheduling Stop and Start.miz index c6d5e8106..a03e37ec9 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-200 - Simple Repeat Scheduling Stop and Start/SCH-200 - Simple Repeat Scheduling Stop and Start.miz and b/Moose Test Missions/SCH - Scheduler/SCH-200 - Simple Repeat Scheduling Stop and Start/SCH-200 - Simple Repeat Scheduling Stop and Start.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-300 - GC Simple Object Scheduling/SCH-300 - GC Simple Object Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-300 - GC Simple Object Scheduling/SCH-300 - GC Simple Object Scheduling.miz index 021de303b..13fffaf1a 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-300 - GC Simple Object Scheduling/SCH-300 - GC Simple Object Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-300 - GC Simple Object Scheduling/SCH-300 - GC Simple Object Scheduling.miz differ diff --git a/Moose Test Missions/SCH - Scheduler/SCH-310 - GC Object Repeat Scheduling/SCH-310 - GC Object Repeat Scheduling.miz b/Moose Test Missions/SCH - Scheduler/SCH-310 - GC Object Repeat Scheduling/SCH-310 - GC Object Repeat Scheduling.miz index 5cab31918..ae0013d4e 100644 Binary files a/Moose Test Missions/SCH - Scheduler/SCH-310 - GC Object Repeat Scheduling/SCH-310 - GC Object Repeat Scheduling.miz and b/Moose Test Missions/SCH - Scheduler/SCH-310 - GC Object Repeat Scheduling/SCH-310 - GC Object Repeat Scheduling.miz differ diff --git a/Moose Test Missions/SET - Data Sets/SET-001 - Airbase Sets/SET-001 - Airbase Sets.miz b/Moose Test Missions/SET - Data Sets/SET-001 - Airbase Sets/SET-001 - Airbase Sets.miz index b32cce74e..264a3b6eb 100644 Binary files a/Moose Test Missions/SET - Data Sets/SET-001 - Airbase Sets/SET-001 - Airbase Sets.miz and b/Moose Test Missions/SET - Data Sets/SET-001 - Airbase Sets/SET-001 - Airbase Sets.miz differ diff --git a/Moose Test Missions/SET - Data Sets/SET-101 - Group Sets/SET-101 - Group Sets.miz b/Moose Test Missions/SET - Data Sets/SET-101 - Group Sets/SET-101 - Group Sets.miz index 7005fd8c2..e1acd9e66 100644 Binary files a/Moose Test Missions/SET - Data Sets/SET-101 - Group Sets/SET-101 - Group Sets.miz and b/Moose Test Missions/SET - Data Sets/SET-101 - Group Sets/SET-101 - Group Sets.miz differ diff --git a/Moose Test Missions/SET - Data Sets/SET-201 - Client Sets/SET-201 - Client Sets.miz b/Moose Test Missions/SET - Data Sets/SET-201 - Client Sets/SET-201 - Client Sets.miz index 54ecbecd7..88d0a84ab 100644 Binary files a/Moose Test Missions/SET - Data Sets/SET-201 - Client Sets/SET-201 - Client Sets.miz and b/Moose Test Missions/SET - Data Sets/SET-201 - Client Sets/SET-201 - Client Sets.miz differ diff --git a/Moose Test Missions/SEV - SEAD Evasion/SEV-001 - SEAD Evasion/SEV-001 - SEAD Evasion.miz b/Moose Test Missions/SEV - SEAD Evasion/SEV-001 - SEAD Evasion/SEV-001 - SEAD Evasion.miz index df92d4792..4353aabf6 100644 Binary files a/Moose Test Missions/SEV - SEAD Evasion/SEV-001 - SEAD Evasion/SEV-001 - SEAD Evasion.miz and b/Moose Test Missions/SEV - SEAD Evasion/SEV-001 - SEAD Evasion/SEV-001 - SEAD Evasion.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-010 - Spawn Demo/SPA-010 - Spawn Demo.miz b/Moose Test Missions/SPA - Spawning/SPA-010 - Spawn Demo/SPA-010 - Spawn Demo.miz index dc401ec98..b86cac3fb 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-010 - Spawn Demo/SPA-010 - Spawn Demo.miz and b/Moose Test Missions/SPA - Spawning/SPA-010 - Spawn Demo/SPA-010 - Spawn Demo.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-100 - CleanUp Inactive Units/SPA-100 - CleanUp Inactive Units.miz b/Moose Test Missions/SPA - Spawning/SPA-100 - CleanUp Inactive Units/SPA-100 - CleanUp Inactive Units.miz index db96ec5c8..f2c616520 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-100 - CleanUp Inactive Units/SPA-100 - CleanUp Inactive Units.miz and b/Moose Test Missions/SPA - Spawning/SPA-100 - CleanUp Inactive Units/SPA-100 - CleanUp Inactive Units.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-110 - Limit Spawning/SPA-110 - Limit Spawning.miz b/Moose Test Missions/SPA - Spawning/SPA-110 - Limit Spawning/SPA-110 - Limit Spawning.miz index 7dec6f673..cf882d95f 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-110 - Limit Spawning/SPA-110 - Limit Spawning.miz and b/Moose Test Missions/SPA - Spawning/SPA-110 - Limit Spawning/SPA-110 - Limit Spawning.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-120 - Repeat Spawning/SPA-120 - Repeat Spawning.miz b/Moose Test Missions/SPA - Spawning/SPA-120 - Repeat Spawning/SPA-120 - Repeat Spawning.miz index 5c6107869..78244fdb3 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-120 - Repeat Spawning/SPA-120 - Repeat Spawning.miz and b/Moose Test Missions/SPA - Spawning/SPA-120 - Repeat Spawning/SPA-120 - Repeat Spawning.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-200 - Randomize Unit Types/SPA-200 - Randomize Unit Types.miz b/Moose Test Missions/SPA - Spawning/SPA-200 - Randomize Unit Types/SPA-200 - Randomize Unit Types.miz index dfac695a6..abf3ba325 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-200 - Randomize Unit Types/SPA-200 - Randomize Unit Types.miz and b/Moose Test Missions/SPA - Spawning/SPA-200 - Randomize Unit Types/SPA-200 - Randomize Unit Types.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-220 - Randomize Zones/SPA-220 - Randomize Zones.miz b/Moose Test Missions/SPA - Spawning/SPA-220 - Randomize Zones/SPA-220 - Randomize Zones.miz index 092d81d69..c9bf73dc3 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-220 - Randomize Zones/SPA-220 - Randomize Zones.miz and b/Moose Test Missions/SPA - Spawning/SPA-220 - Randomize Zones/SPA-220 - Randomize Zones.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-310 - Spawn at Static position/SPA-310 - Spawn at Static position.miz b/Moose Test Missions/SPA - Spawning/SPA-310 - Spawn at Static position/SPA-310 - Spawn at Static position.miz index 868b23385..122e41d80 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-310 - Spawn at Static position/SPA-310 - Spawn at Static position.miz and b/Moose Test Missions/SPA - Spawning/SPA-310 - Spawn at Static position/SPA-310 - Spawn at Static position.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-320 - Spawn at Unit position/SPA-320 - Spawn at Unit position.miz b/Moose Test Missions/SPA - Spawning/SPA-320 - Spawn at Unit position/SPA-320 - Spawn at Unit position.miz index 2b4440766..4f02b5b68 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-320 - Spawn at Unit position/SPA-320 - Spawn at Unit position.miz and b/Moose Test Missions/SPA - Spawning/SPA-320 - Spawn at Unit position/SPA-320 - Spawn at Unit position.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-330 - Spawn at Vec2 position/SPA-330 - Spawn at Vec2 position.miz b/Moose Test Missions/SPA - Spawning/SPA-330 - Spawn at Vec2 position/SPA-330 - Spawn at Vec2 position.miz index 1af97b8bf..b490ea793 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-330 - Spawn at Vec2 position/SPA-330 - Spawn at Vec2 position.miz and b/Moose Test Missions/SPA - Spawning/SPA-330 - Spawn at Vec2 position/SPA-330 - Spawn at Vec2 position.miz differ diff --git a/Moose Test Missions/SPA - Spawning/SPA-340 - Spawn at Vec3 position/SPA-340 - Spawn at Vec3 position.miz b/Moose Test Missions/SPA - Spawning/SPA-340 - Spawn at Vec3 position/SPA-340 - Spawn at Vec3 position.miz index 1dff8f823..02b954617 100644 Binary files a/Moose Test Missions/SPA - Spawning/SPA-340 - Spawn at Vec3 position/SPA-340 - Spawn at Vec3 position.miz and b/Moose Test Missions/SPA - Spawning/SPA-340 - Spawn at Vec3 position/SPA-340 - Spawn at Vec3 position.miz differ diff --git a/Moose Test Missions/TAD - Task Dispatching/TAD-010 - Task Dispatching Demo/TAD-010 - Task Dispatching Demo.miz b/Moose Test Missions/TAD - Task Dispatching/TAD-010 - Task Dispatching Demo/TAD-010 - Task Dispatching Demo.miz index 9d49df0e8..d08fae6f6 100644 Binary files a/Moose Test Missions/TAD - Task Dispatching/TAD-010 - Task Dispatching Demo/TAD-010 - Task Dispatching Demo.miz and b/Moose Test Missions/TAD - Task Dispatching/TAD-010 - Task Dispatching Demo/TAD-010 - Task Dispatching Demo.miz differ diff --git a/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.lua b/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.lua index 17526a9c1..520e32cec 100644 --- a/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.lua +++ b/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.lua @@ -506,7 +506,7 @@ SEADProcess:AddScoreProcess( "Updated", "Account", "Failed", "failed to destroy SEADProcess:AddScore( "Success", "Destroyed all target radars", 250 ) SEADProcess:AddScore( "Failed", "Failed to destroy all target radars", -100 ) -function SEADProcess:OnEnterUpdated(Controllable,From,Event,To) +function SEADProcess:OnEnterUpdated( Controllable, From, Event, To ) self:E( { self } ) self:Account() self:Smoke() @@ -517,7 +517,7 @@ end -- we check if the SEADTask has still AlivePlayers assigned to the Task. -- If not, the Task will Abort. -- And it will be Replanned within 30 seconds. -function SEADTask:OnAfterPlayerCrashed( PlayerUnit, PlayerName ) +function SEADTask:OnEnterPlayerCrashed( PlayerUnit, PlayerName ) if not SEADTask:HasAliveUnits() then SEADTask:__Abort() SEADTask:__Replan( 30 ) diff --git a/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.miz b/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.miz index aa3d43398..1719c30bc 100644 Binary files a/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.miz and b/Moose Test Missions/TSK - Task Modelling/TSK-010 - Task Modelling - SEAD/TSK-010 - Task Modelling - SEAD.miz differ diff --git a/Moose Test Missions/TSK - Task Modelling/TSK-020 - Task Modelling - Pickup/TSK-020 - Task Modelling - Pickup.miz b/Moose Test Missions/TSK - Task Modelling/TSK-020 - Task Modelling - Pickup/TSK-020 - Task Modelling - Pickup.miz index f6d0adc6e..544031d16 100644 Binary files a/Moose Test Missions/TSK - Task Modelling/TSK-020 - Task Modelling - Pickup/TSK-020 - Task Modelling - Pickup.miz and b/Moose Test Missions/TSK - Task Modelling/TSK-020 - Task Modelling - Pickup/TSK-020 - Task Modelling - Pickup.miz differ diff --git a/Moose Test Missions/ZON - Zones/ZON-100 - Normal Zone/ZON-100 - Normal Zone.miz b/Moose Test Missions/ZON - Zones/ZON-100 - Normal Zone/ZON-100 - Normal Zone.miz index 6deec88ca..a3ed681d6 100644 Binary files a/Moose Test Missions/ZON - Zones/ZON-100 - Normal Zone/ZON-100 - Normal Zone.miz and b/Moose Test Missions/ZON - Zones/ZON-100 - Normal Zone/ZON-100 - Normal Zone.miz differ diff --git a/Moose Test Missions/ZON - Zones/ZON-200 - Group Zone/ZON-200 - Group Zone.miz b/Moose Test Missions/ZON - Zones/ZON-200 - Group Zone/ZON-200 - Group Zone.miz index 4925e1a7d..05a815e9f 100644 Binary files a/Moose Test Missions/ZON - Zones/ZON-200 - Group Zone/ZON-200 - Group Zone.miz and b/Moose Test Missions/ZON - Zones/ZON-200 - Group Zone/ZON-200 - Group Zone.miz differ diff --git a/Moose Test Missions/ZON - Zones/ZON-300 - Unit Zone/ZON-300 - Unit Zone.miz b/Moose Test Missions/ZON - Zones/ZON-300 - Unit Zone/ZON-300 - Unit Zone.miz index 396b71f4e..cf0c1d0be 100644 Binary files a/Moose Test Missions/ZON - Zones/ZON-300 - Unit Zone/ZON-300 - Unit Zone.miz and b/Moose Test Missions/ZON - Zones/ZON-300 - Unit Zone/ZON-300 - Unit Zone.miz differ diff --git a/Moose Test Missions/ZON - Zones/ZON-400 - Radius Zone/ZON-400 - Radius Zone.miz b/Moose Test Missions/ZON - Zones/ZON-400 - Radius Zone/ZON-400 - Radius Zone.miz index 9cb111f0c..39798510b 100644 Binary files a/Moose Test Missions/ZON - Zones/ZON-400 - Radius Zone/ZON-400 - Radius Zone.miz and b/Moose Test Missions/ZON - Zones/ZON-400 - Radius Zone/ZON-400 - Radius Zone.miz differ diff --git a/Moose Test Missions/ZON - Zones/ZON-500 - Polygon Zone/ZON-500 - Polygon Zone.miz b/Moose Test Missions/ZON - Zones/ZON-500 - Polygon Zone/ZON-500 - Polygon Zone.miz index ac7801ef1..1a3282c7b 100644 Binary files a/Moose Test Missions/ZON - Zones/ZON-500 - Polygon Zone/ZON-500 - Polygon Zone.miz and b/Moose Test Missions/ZON - Zones/ZON-500 - Polygon Zone/ZON-500 - Polygon Zone.miz differ diff --git a/docs/Documentation/AI_Balancer.html b/docs/Documentation/AI_Balancer.html index 15d059e29..f3d1ca87e 100644 --- a/docs/Documentation/AI_Balancer.html +++ b/docs/Documentation/AI_Balancer.html @@ -68,42 +68,80 @@

Module AI_Balancer

-

This module contains the AI_BALANCER class.

+

SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class.

+

AI Balancing will replace in multi player missions non-occupied human slots with AI groups, in order to provide an +engaging simulation environment, even when there are hardly any players in the mission.

+ +

Banner Image

+

1) AI.AIBalancer#AIBALANCER class, extends Core.Fsm#FSM_SET

+

The AI.AIBalancer#AIBALANCER class monitors and manages as many AI GROUPS as there are -CLIENTS in a SETCLIENT collection not occupied by players. -The AIBALANCER class manages internally a collection of AI management objects, which govern the behaviour -of the underlying AI GROUPS.

+CLIENTS in a SETCLIENT collection not occupied by human players. +In other words, use AIBALANCER to simulate human behaviour by spawning in replacement AI.

-

The parent class Core.Fsm#FSM_SET manages the functionality to control the Finite State Machine (FSM) +

The AI_BALANCER class manages internally a collection of AI management objects, which govern the behaviour +of the spawned AI Wrapper.Group#GROUP manages the functionality to control the Finite State Machine (FSM) and calls for each event the state transition methods providing the internal Core.Fsm#FSM_SET.Set object containing the -SET_GROUP and additional event parameters provided during the event.

+AI and additional event parameters provided during the event.

-

1.1) AI_BALANCER construction method

-

Create a new AI_BALANCER object with the AI_BALANCER.New method:

+

1.1) AI_BALANCER construction

+ +

Create a new AI_BALANCER object with the AI_BALANCER.New() method:

+ +

1.2) AI_BALANCER is a FSM

+ +

The AI_BALANCER is a state machine: it manages the different events and states of the Core.Fsm#FSM_SET.Set it is governing. +The AI_BALANCER has a default flow to manage the set.

+ +

Process

+ + +

1.2.1) AI_BALANCER States

    -
  • AI_BALANCER.New: Creates a new AI_BALANCER object.
  • +
  • Monitoring ( Set ): Monitoring the Set if all AI is spawned for the Clients.
  • +
  • Spawning ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference.
  • +
  • Spawned ( Set, AIGroup ): A new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes.
  • +
  • Destroying ( Set, AIGroup ): The AI is being destroyed.
  • +
  • Returning ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods. Handle this state to customize the return behaviour of the AI, if any.
-

1.2)

-

* Add - * Remove

- -

1.2) AI_BALANCER returns AI to Airbases

-

You can configure to have the AI to return to:

+

1.2.2) AI_BALANCER Events

    -
  • AI_BALANCER.ReturnToHomeAirbase: Returns the AI to the home Wrapper.Airbase#AIRBASE.
  • -
  • AI_BALANCER.ReturnToNearestAirbases: Returns the AI to the nearest friendly Wrapper.Airbase#AIRBASE. - --
  • +
  • Monitor ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set.
  • +
  • Spawn ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference.
  • +
  • Spawned ( Set, AIGroup ): Triggers when a new AI has been spawned. You can handle this event to customize the AI behaviour with other AI FSMs or own processes.
  • +
  • Destroy ( Set, AIGroup ): The AI is being destroyed.
  • +
  • Return ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods.
+

1.3) AI_BALANCER spawn interval for replacement AI

+ +

Use the method AI_BALANCER.InitSpawnInterval() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned.

+ +

1.4) AI_BALANCER returns AI to Airbases

+ +

By default, When a human player joins a slot that is AI_BALANCED, the AI group will be destroyed by default. +However, there are 2 additional options that you can use to customize the destroy behaviour. +When a human player joins a slot, you can configure to let the AI return to:

+ + + +

Note that when AI returns to an airbase, it will trigger the Return event and will return, +otherwise when the AI is destroyed, the Destroy event will be triggered.

+ +
+

API CHANGE HISTORY

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

@@ -115,32 +153,23 @@ SET_GROUP and additional event parameters provided during the event.

Hereby the change log:

-

2016-08-17: SPAWN:InitCleanUp( SpawnCleanUpInterval ) replaces SPAWN:CleanUp( SpawnCleanUpInterval )

- -
    -
  • Want to ensure that the methods starting with Init are the first called methods before any Spawn method is called!
  • -
  • This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods.
  • -
+

2017-01-08: AI_BALANCER:InitSpawnInterval( Earliest, Latest ) added.


-

AUTHORS and CONTRIBUTIONS

+

AUTHORS and CONTRIBUTIONS

Contributions:

    -
  • Dutch_Baron (James): Who you can search on the Eagle Dynamics Forums.
    - Working together with James has resulted in the creation of the AI_BALANCER class.
    - James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)

  • -
  • SNAFU: - Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. - None of the script code has been used however within the new AI_BALANCER moose class.

  • +
  • Dutch_Baron: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)

  • +
  • SNAFU: Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. None of the script code has been used however within the new AI_BALANCER moose class.

Authors:

    -
  • FlightControl: Framework Design & Programming
  • +
  • FlightControl: Framework Design & Programming and Documentation.
@@ -165,6 +194,24 @@ SET_GROUP and additional event parameters provided during the event.

AI_BALANCER.ClassName + + + + AI_BALANCER.Earliest + + + + + + AI_BALANCER:InitSpawnInterval(Earliest, Latest) + +

Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI.

+ + + + AI_BALANCER.Latest + + @@ -207,6 +254,18 @@ SET_GROUP and additional event parameters provided during the event.

AI_BALANCER.SetClient + + + + AI_BALANCER.SpawnAI + + + + + + AI_BALANCER.Test + + @@ -222,7 +281,7 @@ SET_GROUP and additional event parameters provided during the event.

- AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To) + AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To, ClientName) @@ -295,6 +354,70 @@ SET_GROUP and additional event parameters provided during the event.

+ + +
+
+ + + +AI_BALANCER.Earliest + +
+
+ + + +
+
+
+
+ + +AI_BALANCER:InitSpawnInterval(Earliest, Latest) + +
+
+ +

Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI.

+ + +

Provide 2 identical seconds if the interval should be a fixed amount of seconds.

+ +

Parameters

+
    +
  • + +

    #number Earliest : +The earliest a new AI can be spawned in seconds.

    + +
  • +
  • + +

    #number Latest : +The latest a new AI can be spawned in seconds.

    + +
  • +
+

Return value

+ + +

self

+ +
+
+
+
+ + + +AI_BALANCER.Latest + +
+
+ + +
@@ -328,9 +451,6 @@ The default Spawn object to spawn new AI Groups when needed.

#AI_BALANCER:

-

Usage:

-
-- Define a new AI_BALANCER Object.
-
@@ -437,6 +557,34 @@ The SET of Core.Set#SET_AIRBASEs to e + +
+
+
+ + Functional.Spawn#SPAWN + +AI_BALANCER.SpawnAI + +
+
+ + + +
+
+
+
+ + Wrapper.Group#GROUP + +AI_BALANCER.Test + +
+
+ + +
@@ -471,7 +619,7 @@ The SET of Core.Set#SET_AIRBASEs to e
-AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To) +AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To, ClientName)
@@ -504,6 +652,11 @@ The SET of Core.Set#SET_AIRBASEs to e

To :

+ +
  • + +

    ClientName :

    +
  • diff --git a/docs/Documentation/Cargo.html b/docs/Documentation/Cargo.html index c03fa6ee7..1f6e80989 100644 --- a/docs/Documentation/Cargo.html +++ b/docs/Documentation/Cargo.html @@ -119,13 +119,13 @@ All derived classes from AICARGO follow the same state machine, expose the There are 2 moments when state transition methods will be called by the state machine:

      -
    • Before the state transition. - The state transition method needs to start with the name OnBefore + the name of the state. +

    • Leaving the state. + The state transition method needs to start with the name OnLeave + the name of the state. If the state transition method returns false, then the processing of the state transition will not be done! If you want to change the behaviour of the AIControllable at this event, return false, but then you'll need to specify your own logic using the AIControllable!

    • -
    • After the state transition. - The state transition method needs to start with the name OnAfter + the name of the state. +

    • Entering the state. + The state transition method needs to start with the name OnEnter + the name of the state. These state transition methods need to provide a return value, which is specified at the function description.

    @@ -254,49 +254,49 @@ Use the event functions as described above to Load, UnLoad, Board, UnBoard the A - AI_CARGO:OnAfterBoarding(Controllable) + AI_CARGO:OnEnterBoarding(Controllable) - AI_CARGO:OnAfterLoaded(Controllable) + AI_CARGO:OnEnterLoaded(Controllable) - AI_CARGO:OnAfterUnBoarding(Controllable) + AI_CARGO:OnEnterUnBoarding(Controllable) - AI_CARGO:OnAfterUnLoaded(Controllable) + AI_CARGO:OnEnterUnLoaded(Controllable) - AI_CARGO:OnBeforeBoarding(Controllable) + AI_CARGO:OnLeaveBoarding(Controllable) - AI_CARGO:OnBeforeLoaded(Controllable) + AI_CARGO:OnLeaveLoaded(Controllable) - AI_CARGO:OnBeforeUnBoarding(Controllable) + AI_CARGO:OnLeaveUnBoarding(Controllable) - AI_CARGO:OnBeforeUnLoaded(Controllable) + AI_CARGO:OnLeaveUnLoaded(Controllable) @@ -974,8 +974,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnAfterBoarding(Controllable) + +AI_CARGO:OnEnterBoarding(Controllable)
    @@ -995,8 +995,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnAfterLoaded(Controllable) + +AI_CARGO:OnEnterLoaded(Controllable)
    @@ -1016,8 +1016,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnAfterUnBoarding(Controllable) + +AI_CARGO:OnEnterUnBoarding(Controllable)
    @@ -1037,8 +1037,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnAfterUnLoaded(Controllable) + +AI_CARGO:OnEnterUnLoaded(Controllable)
    @@ -1058,8 +1058,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnBeforeBoarding(Controllable) + +AI_CARGO:OnLeaveBoarding(Controllable)
    @@ -1084,8 +1084,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnBeforeLoaded(Controllable) + +AI_CARGO:OnLeaveLoaded(Controllable)
    @@ -1110,8 +1110,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnBeforeUnBoarding(Controllable) + +AI_CARGO:OnLeaveUnBoarding(Controllable)
    @@ -1136,8 +1136,8 @@ The Carrier that will hold the cargo.

    - -AI_CARGO:OnBeforeUnLoaded(Controllable) + +AI_CARGO:OnLeaveUnLoaded(Controllable)
    diff --git a/docs/Documentation/Fsm.html b/docs/Documentation/Fsm.html index 87231267a..f1ae7d8f6 100644 --- a/docs/Documentation/Fsm.html +++ b/docs/Documentation/Fsm.html @@ -464,12 +464,24 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added

    FSM:AddTransition(From, Event, To)

    Add a new transition rule to the FSM.

    + + + + FSM.CallScheduler + + FSM.ClassName + + + + FSM.Events + + @@ -536,18 +548,48 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added

    FSM:New(FsmT)

    Creates a new FSM object.

    + + + + FSM.Scores + + FSM:SetStartState(State)

    Sets the start state of the FSM.

    + + + + FSM._EndStates + + + + + + FSM._Processes + + + + + + FSM._Scores + + FSM._StartState + + + + FSM._Transitions + + @@ -620,12 +662,30 @@ YYYY-MM-DD: CLASS:NewFunction( Params ) added

    FSM.current + + + + FSM.endstates + + FSM:is(state) + + + + FSM.options + + + + + + FSM.subs + + @@ -1101,6 +1161,20 @@ The To state.

    +
    +
    +
    +
    + + + +FSM.CallScheduler + +
    +
    + + +
    @@ -1115,6 +1189,20 @@ The To state.

    +
    +
    +
    +
    + + + +FSM.Events + +
    +
    + + +
    @@ -1315,6 +1403,20 @@ A string containing the start state.

    #FSM:

    +
    +
    +
    +
    + + + +FSM.Scores + +
    +
    + + +
    @@ -1343,6 +1445,48 @@ A string defining the start state.

    + +FSM._EndStates + +
    +
    + + + +
    +
    +
    +
    + + + +FSM._Processes + +
    +
    + + + +
    +
    +
    +
    + + + +FSM._Scores + +
    +
    + + + +
    +
    +
    +
    + + #string FSM._StartState @@ -1351,6 +1495,20 @@ A string defining the start state.

    +
    +
    +
    +
    + + + +FSM._Transitions + +
    +
    + + +
    @@ -1622,7 +1780,6 @@ A string defining the start state.

    - FSM.current @@ -1631,6 +1788,20 @@ A string defining the start state.

    +
    +
    +
    +
    + + + +FSM.endstates + +
    +
    + + +
    @@ -1652,6 +1823,33 @@ A string defining the start state.

    +
    +
    +
    +
    + + +FSM.options + +
    +
    + + + +
    +
    +
    +
    + + + +FSM.subs + +
    +
    + + +
    diff --git a/docs/Documentation/Object.html b/docs/Documentation/Object.html index 3e581eb53..6ffdd669c 100644 --- a/docs/Documentation/Object.html +++ b/docs/Documentation/Object.html @@ -138,7 +138,7 @@ - OBJECT:New(ObjectName) + OBJECT:New(ObjectName, Test)

    Create a new OBJECT from a DCSObject

    @@ -256,20 +256,25 @@ The DCS Object is not existing or alive.

    -OBJECT:New(ObjectName) +OBJECT:New(ObjectName, Test)

    Create a new OBJECT from a DCSObject

    -

    Parameter

    +

    Parameters

    Return value

    diff --git a/docs/Documentation/Set.html b/docs/Documentation/Set.html index 7fcf7b511..ea9e68ccc 100644 --- a/docs/Documentation/Set.html +++ b/docs/Documentation/Set.html @@ -470,6 +470,12 @@ The following iterator methods are currently available within the SETAIRBAS SET_BASE:AddObject(Object)

    Adds a Core.Base#BASE object in the Core.Set#SET_BASE, using the Object Name as the index.

    + + + + SET_BASE.CallScheduler + + @@ -1600,6 +1606,20 @@ The added BASE Object.

    Core.Base#BASE: The added BASE Object.

    +
    +
    +
    +
    + + Core.Scheduler#SCHEDULER + +SET_BASE.CallScheduler + +
    +
    + + +
    diff --git a/docs/Documentation/Spawn.html b/docs/Documentation/Spawn.html index 6b5623a9b..1116db12a 100644 --- a/docs/Documentation/Spawn.html +++ b/docs/Documentation/Spawn.html @@ -1692,6 +1692,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.

    +
    diff --git a/docs/Documentation/index.html b/docs/Documentation/index.html index 43e3670b1..eb057e969 100644 --- a/docs/Documentation/index.html +++ b/docs/Documentation/index.html @@ -71,7 +71,7 @@ AI_Balancer -

    This module contains the AI_BALANCER class.

    +

    SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class.

    diff --git a/docs/Presentations/AI_Balancer/AI_BALANCER.pptx b/docs/Presentations/AI_Balancer/AI_BALANCER.pptx new file mode 100644 index 000000000..e04e36ce5 Binary files /dev/null and b/docs/Presentations/AI_Balancer/AI_BALANCER.pptx differ diff --git a/docs/Presentations/AI_Balancer/Dia1.JPG b/docs/Presentations/AI_Balancer/Dia1.JPG new file mode 100644 index 000000000..21fba47d1 Binary files /dev/null and b/docs/Presentations/AI_Balancer/Dia1.JPG differ diff --git a/docs/Presentations/AI_Balancer/Dia2.JPG b/docs/Presentations/AI_Balancer/Dia2.JPG new file mode 100644 index 000000000..8561199f4 Binary files /dev/null and b/docs/Presentations/AI_Balancer/Dia2.JPG differ