mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge pull request #186 from FlightControl-Master/FlightControl
-- Revised and Added documentation. -- Added pictures to documentation. -- Add/Exit clients is working. AI balances perfectly. -- FSM bug fixed. SUBS should not execute OnAfter, OnEnter
This commit is contained in:
commit
ccc10e5233
@ -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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- ### 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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 )
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -207,6 +207,7 @@ SPAWN = {
|
||||
SpawnAliasPrefix = nil,
|
||||
}
|
||||
|
||||
|
||||
--- @type SPAWN.SpawnZoneTable
|
||||
-- @list <Core.Zone#ZONE_BASE> SpawnZone
|
||||
|
||||
|
||||
@ -883,4 +883,3 @@ function GROUP:CalculateThreatLevelA2G()
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
)
|
||||
@ -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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 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.
|
||||
-- 
|
||||
--
|
||||
-- * 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**.
|
||||
--
|
||||
-- 
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
-- ## 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
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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 <Core.Zone#ZONE_BASE> 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- ### 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
|
||||
|
||||
|
||||
@ -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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 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.
|
||||
-- 
|
||||
--
|
||||
-- * 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**.
|
||||
--
|
||||
-- 
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
-- ## 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
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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 <Core.Zone#ZONE_BASE> 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- ### 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
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -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
|
||||
end
|
||||
|
||||
Binary file not shown.
@ -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" )
|
||||
|
||||
Binary file not shown.
@ -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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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 )
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -68,42 +68,80 @@
|
||||
<div id="content">
|
||||
<h1>Module <code>AI_Balancer</code></h1>
|
||||
|
||||
<p>This module contains the AI_BALANCER class.</p>
|
||||
<p>SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class.</p>
|
||||
|
||||
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p><img src="..\Presentations\AI_Balancer\Dia1.JPG" alt="Banner Image"/></p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h1>1) <a href="AI.AI_Balancer.html##(AI_BALANCER)">AI.AI<em>Balancer#AI</em>BALANCER</a> class, extends <a href="Core.Fsm.html##(FSM_SET)">Core.Fsm#FSM_SET</a></h1>
|
||||
|
||||
<p>The <a href="AI.AI_Balancer.html##(AI_BALANCER)">AI.AI<em>Balancer#AI</em>BALANCER</a> class monitors and manages as many AI GROUPS as there are
|
||||
CLIENTS in a SET<em>CLIENT collection not occupied by players.
|
||||
The AI</em>BALANCER class manages internally a collection of AI management objects, which govern the behaviour
|
||||
of the underlying AI GROUPS.</p>
|
||||
CLIENTS in a SET<em>CLIENT collection not occupied by human players.
|
||||
In other words, use AI</em>BALANCER to simulate human behaviour by spawning in replacement AI.</p>
|
||||
|
||||
<p>The parent class <a href="Core.Fsm.html##(FSM_SET)">Core.Fsm#FSM_SET</a> manages the functionality to control the Finite State Machine (FSM)
|
||||
<p>The AI_BALANCER class manages internally a collection of AI management objects, which govern the behaviour
|
||||
of the spawned AI <a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a> manages the functionality to control the Finite State Machine (FSM)
|
||||
and calls for each event the state transition methods providing the internal <a href="Core.Fsm.html##(FSM_SET).Set">Core.Fsm#FSM_SET.Set</a> object containing the
|
||||
SET_GROUP and additional event parameters provided during the event.</p>
|
||||
AI and additional event parameters provided during the event.</p>
|
||||
|
||||
<h2>1.1) AI_BALANCER construction method</h2>
|
||||
<p>Create a new AI_BALANCER object with the <a href="##(AI_BALANCER).New">AI_BALANCER.New</a> method:</p>
|
||||
<h2>1.1) AI_BALANCER construction</h2>
|
||||
|
||||
<p>Create a new AI_BALANCER object with the <a href="##(AI_BALANCER).New">AI_BALANCER.New</a>() method:</p>
|
||||
|
||||
<h2>1.2) AI_BALANCER is a FSM</h2>
|
||||
|
||||
<p>The AI_BALANCER is a state machine: it manages the different events and states of the <a href="Core.Fsm.html##(FSM_SET).Set">Core.Fsm#FSM_SET.Set</a> it is governing.
|
||||
The AI_BALANCER has a default flow to manage the set.</p>
|
||||
|
||||
<p><img src="..\Presentations\AI_Balancer\Dia2.JPG" alt="Process"/></p>
|
||||
|
||||
|
||||
<h3>1.2.1) AI_BALANCER States</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="##(AI_BALANCER).New">AI_BALANCER.New</a>: Creates a new AI_BALANCER object.</li>
|
||||
<li><strong>Monitoring</strong> ( Set ): Monitoring the Set if all AI is spawned for the Clients.</li>
|
||||
<li><strong>Spawning</strong> ( Set, ClientName ): There is a new AI group spawned with ClientName as the name of reference.</li>
|
||||
<li><strong>Spawned</strong> ( 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.</li>
|
||||
<li><strong>Destroying</strong> ( Set, AIGroup ): The AI is being destroyed.</li>
|
||||
<li><strong>Returning</strong> ( 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.</li>
|
||||
</ul>
|
||||
|
||||
<h2>1.2) </h2>
|
||||
<p> * Add
|
||||
* Remove</p>
|
||||
|
||||
<h2>1.2) AI_BALANCER returns AI to Airbases</h2>
|
||||
<p>You can configure to have the AI to return to:</p>
|
||||
<h3>1.2.2) AI_BALANCER Events</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="##(AI_BALANCER).ReturnToHomeAirbase">AI_BALANCER.ReturnToHomeAirbase</a>: Returns the AI to the home <a href="Wrapper.Airbase.html##(AIRBASE)">Wrapper.Airbase#AIRBASE</a>.</li>
|
||||
<li><a href="##(AI_BALANCER).ReturnToNearestAirbases">AI_BALANCER.ReturnToNearestAirbases</a>: Returns the AI to the nearest friendly <a href="Wrapper.Airbase.html##(AIRBASE)">Wrapper.Airbase#AIRBASE</a>.
|
||||
--</li>
|
||||
<li><strong>Monitor</strong> ( Set ): Every 10 seconds, the Monitor event is triggered to monitor the Set.</li>
|
||||
<li><strong>Spawn</strong> ( Set, ClientName ): Triggers when there is a new AI group to be spawned with ClientName as the name of reference.</li>
|
||||
<li><strong>Spawned</strong> ( 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.</li>
|
||||
<li><strong>Destroy</strong> ( Set, AIGroup ): The AI is being destroyed.</li>
|
||||
<li><strong>Return</strong> ( Set, AIGroup ): The AI is returning to the airbase specified by the ReturnToAirbase methods.</li>
|
||||
</ul>
|
||||
|
||||
<h2>1.3) AI_BALANCER spawn interval for replacement AI</h2>
|
||||
|
||||
<p>Use the method <a href="##(AI_BALANCER).InitSpawnInterval">AI_BALANCER.InitSpawnInterval</a>() to set the earliest and latest interval in seconds that is waited until a new replacement AI is spawned.</p>
|
||||
|
||||
<h2>1.4) AI_BALANCER returns AI to Airbases</h2>
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="##(AI_BALANCER).ReturnToHomeAirbase">AI_BALANCER.ReturnToHomeAirbase</a>: Returns the AI to the <strong>home</strong> <a href="Wrapper.Airbase.html##(AIRBASE)">Wrapper.Airbase#AIRBASE</a>.</li>
|
||||
<li><a href="##(AI_BALANCER).ReturnToNearestAirbases">AI_BALANCER.ReturnToNearestAirbases</a>: Returns the AI to the <strong>nearest friendly</strong> <a href="Wrapper.Airbase.html##(AIRBASE)">Wrapper.Airbase#AIRBASE</a>.</li>
|
||||
</ul>
|
||||
|
||||
<p>Note that when AI returns to an airbase, it will trigger the <strong>Return</strong> event and will return,
|
||||
otherwise when the AI is destroyed, the <strong>Destroy</strong> event will be triggered.</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h1><strong>API CHANGE HISTORY</strong></h1>
|
||||
|
||||
<p>The underlying change log documents the API changes. Please read this carefully. The following notation is used:</p>
|
||||
@ -115,32 +153,23 @@ SET_GROUP and additional event parameters provided during the event.</p>
|
||||
|
||||
<p>Hereby the change log:</p>
|
||||
|
||||
<p>2016-08-17: SPAWN:<strong>InitCleanUp</strong>( SpawnCleanUpInterval ) replaces SPAWN:<em>CleanUp</em>( SpawnCleanUpInterval )</p>
|
||||
|
||||
<ul>
|
||||
<li>Want to ensure that the methods starting with <strong>Init</strong> are the first called methods before any <em>Spawn</em> method is called!</li>
|
||||
<li>This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods.</li>
|
||||
</ul>
|
||||
<p>2017-01-08: AI_BALANCER:<strong>InitSpawnInterval( Earliest, Latest )</strong> added.</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h1>AUTHORS and CONTRIBUTIONS</h1>
|
||||
<h1><strong>AUTHORS and CONTRIBUTIONS</strong></h1>
|
||||
|
||||
<h3>Contributions:</h3>
|
||||
|
||||
<ul>
|
||||
<li><p><strong>Dutch_Baron (James)</strong>: Who you can search on the Eagle Dynamics Forums. <br/>
|
||||
Working together with James has resulted in the creation of the AI_BALANCER class. <br/>
|
||||
James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)</p></li>
|
||||
<li><p><strong>SNAFU</strong>:
|
||||
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.</p></li>
|
||||
<li><p><strong><a href="https://forums.eagle.ru/member.php?u=112075">Dutch_Baron</a></strong>: 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 :-)</p></li>
|
||||
<li><p><strong>SNAFU</strong>: 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.</p></li>
|
||||
</ul>
|
||||
|
||||
<h3>Authors:</h3>
|
||||
|
||||
<ul>
|
||||
<li>FlightControl: Framework Design & Programming</li>
|
||||
<li>FlightControl: Framework Design & Programming and Documentation.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@ -165,6 +194,24 @@ SET_GROUP and additional event parameters provided during the event.</p>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).ClassName">AI_BALANCER.ClassName</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).Earliest">AI_BALANCER.Earliest</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).InitSpawnInterval">AI_BALANCER:InitSpawnInterval(Earliest, Latest)</a></td>
|
||||
<td class="summary">
|
||||
<p>Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).Latest">AI_BALANCER.Latest</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -207,6 +254,18 @@ SET_GROUP and additional event parameters provided during the event.</p>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).SetClient">AI_BALANCER.SetClient</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).SpawnAI">AI_BALANCER.SpawnAI</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).Test">AI_BALANCER.Test</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -222,7 +281,7 @@ SET_GROUP and additional event parameters provided during the event.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).onenterDestroying">AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_BALANCER).onenterDestroying">AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To, ClientName)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
@ -295,6 +354,70 @@ SET_GROUP and additional event parameters provided during the event.</p>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(AI_BALANCER).Earliest" >
|
||||
<strong>AI_BALANCER.Earliest</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_BALANCER).InitSpawnInterval" >
|
||||
<strong>AI_BALANCER:InitSpawnInterval(Earliest, Latest)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<p>Sets the earliest to the latest interval in seconds how long AI_BALANCER will wait to spawn a new AI.</p>
|
||||
|
||||
|
||||
<p>Provide 2 identical seconds if the interval should be a fixed amount of seconds.</p>
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<p><code><em>#number Earliest </em></code>:
|
||||
The earliest a new AI can be spawned in seconds.</p>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<p><code><em>#number Latest </em></code>:
|
||||
The latest a new AI can be spawned in seconds.</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Return value</h3>
|
||||
|
||||
|
||||
<p>self</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(AI_BALANCER).Latest" >
|
||||
<strong>AI_BALANCER.Latest</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -328,9 +451,6 @@ The default Spawn object to spawn new AI Groups when needed.</p>
|
||||
<p><em><a href="##(AI_BALANCER)">#AI_BALANCER</a>:</em></p>
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<pre class="example"><code>-- Define a new AI_BALANCER Object.</code></pre>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -437,6 +557,34 @@ The SET of <a href="Core.Set.html##(SET_AIRBASE)">Core.Set#SET_AIRBASE</a>s to e
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em><a href="Functional.Spawn.html##(SPAWN)">Functional.Spawn#SPAWN</a></em>
|
||||
<a id="#(AI_BALANCER).SpawnAI" >
|
||||
<strong>AI_BALANCER.SpawnAI</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em><a href="Wrapper.Group.html##(GROUP)">Wrapper.Group#GROUP</a></em>
|
||||
<a id="#(AI_BALANCER).Test" >
|
||||
<strong>AI_BALANCER.Test</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -471,7 +619,7 @@ The SET of <a href="Core.Set.html##(SET_AIRBASE)">Core.Set#SET_AIRBASE</a>s to e
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_BALANCER).onenterDestroying" >
|
||||
<strong>AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To)</strong>
|
||||
<strong>AI_BALANCER:onenterDestroying(SetGroup, AIGroup, From, Event, To, ClientName)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -504,6 +652,11 @@ The SET of <a href="Core.Set.html##(SET_AIRBASE)">Core.Set#SET_AIRBASE</a>s to e
|
||||
|
||||
<p><code><em> To </em></code>: </p>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<p><code><em> ClientName </em></code>: </p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
|
||||
@ -119,13 +119,13 @@ All derived classes from AI</em>CARGO follow the same state machine, expose the
|
||||
There are 2 moments when state transition methods will be called by the state machine:</p>
|
||||
|
||||
<ul>
|
||||
<li><p><strong>Before</strong> the state transition.
|
||||
The state transition method needs to start with the name <strong>OnBefore + the name of the state</strong>.
|
||||
<li><p><strong>Leaving</strong> the state.
|
||||
The state transition method needs to start with the name <strong>OnLeave + the name of the state</strong>.
|
||||
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!</p></li>
|
||||
<li><p><strong>After</strong> the state transition.
|
||||
The state transition method needs to start with the name <strong>OnAfter + the name of the state</strong>.
|
||||
<li><p><strong>Entering</strong> the state.
|
||||
The state transition method needs to start with the name <strong>OnEnter + the name of the state</strong>.
|
||||
These state transition methods need to provide a return value, which is specified at the function description.</p></li>
|
||||
</ul>
|
||||
|
||||
@ -254,49 +254,49 @@ Use the event functions as described above to Load, UnLoad, Board, UnBoard the A
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnAfterBoarding">AI_CARGO:OnAfterBoarding(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnEnterBoarding">AI_CARGO:OnEnterBoarding(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnAfterLoaded">AI_CARGO:OnAfterLoaded(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnEnterLoaded">AI_CARGO:OnEnterLoaded(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnAfterUnBoarding">AI_CARGO:OnAfterUnBoarding(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnEnterUnBoarding">AI_CARGO:OnEnterUnBoarding(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnAfterUnLoaded">AI_CARGO:OnAfterUnLoaded(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnEnterUnLoaded">AI_CARGO:OnEnterUnLoaded(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnBeforeBoarding">AI_CARGO:OnBeforeBoarding(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnLeaveBoarding">AI_CARGO:OnLeaveBoarding(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnBeforeLoaded">AI_CARGO:OnBeforeLoaded(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnLeaveLoaded">AI_CARGO:OnLeaveLoaded(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnBeforeUnBoarding">AI_CARGO:OnBeforeUnBoarding(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnLeaveUnBoarding">AI_CARGO:OnLeaveUnBoarding(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnBeforeUnLoaded">AI_CARGO:OnBeforeUnLoaded(Controllable)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(AI_CARGO).OnLeaveUnLoaded">AI_CARGO:OnLeaveUnLoaded(Controllable)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
@ -974,8 +974,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnAfterBoarding" >
|
||||
<strong>AI_CARGO:OnAfterBoarding(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnEnterBoarding" >
|
||||
<strong>AI_CARGO:OnEnterBoarding(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -995,8 +995,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnAfterLoaded" >
|
||||
<strong>AI_CARGO:OnAfterLoaded(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnEnterLoaded" >
|
||||
<strong>AI_CARGO:OnEnterLoaded(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1016,8 +1016,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnAfterUnBoarding" >
|
||||
<strong>AI_CARGO:OnAfterUnBoarding(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnEnterUnBoarding" >
|
||||
<strong>AI_CARGO:OnEnterUnBoarding(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1037,8 +1037,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnAfterUnLoaded" >
|
||||
<strong>AI_CARGO:OnAfterUnLoaded(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnEnterUnLoaded" >
|
||||
<strong>AI_CARGO:OnEnterUnLoaded(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1058,8 +1058,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnBeforeBoarding" >
|
||||
<strong>AI_CARGO:OnBeforeBoarding(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnLeaveBoarding" >
|
||||
<strong>AI_CARGO:OnLeaveBoarding(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1084,8 +1084,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnBeforeLoaded" >
|
||||
<strong>AI_CARGO:OnBeforeLoaded(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnLeaveLoaded" >
|
||||
<strong>AI_CARGO:OnLeaveLoaded(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1110,8 +1110,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnBeforeUnBoarding" >
|
||||
<strong>AI_CARGO:OnBeforeUnBoarding(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnLeaveUnBoarding" >
|
||||
<strong>AI_CARGO:OnLeaveUnBoarding(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
@ -1136,8 +1136,8 @@ The Carrier that will hold the cargo.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(AI_CARGO).OnBeforeUnLoaded" >
|
||||
<strong>AI_CARGO:OnBeforeUnLoaded(Controllable)</strong>
|
||||
<a id="#(AI_CARGO).OnLeaveUnLoaded" >
|
||||
<strong>AI_CARGO:OnLeaveUnLoaded(Controllable)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
@ -464,12 +464,24 @@ YYYY-MM-DD: CLASS:<strong>NewFunction( Params )</strong> added</p>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).AddTransition">FSM:AddTransition(From, Event, To)</a></td>
|
||||
<td class="summary">
|
||||
<p>Add a new transition rule to the FSM.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).CallScheduler">FSM.CallScheduler</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).ClassName">FSM.ClassName</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).Events">FSM.Events</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -536,18 +548,48 @@ YYYY-MM-DD: CLASS:<strong>NewFunction( Params )</strong> added</p>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).New">FSM:New(FsmT)</a></td>
|
||||
<td class="summary">
|
||||
<p>Creates a new FSM object.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).Scores">FSM.Scores</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).SetStartState">FSM:SetStartState(State)</a></td>
|
||||
<td class="summary">
|
||||
<p>Sets the start state of the FSM.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM)._EndStates">FSM._EndStates</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM)._Processes">FSM._Processes</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM)._Scores">FSM._Scores</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM)._StartState">FSM._StartState</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM)._Transitions">FSM._Transitions</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -620,12 +662,30 @@ YYYY-MM-DD: CLASS:<strong>NewFunction( Params )</strong> added</p>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).current">FSM.current</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).endstates">FSM.endstates</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).is">FSM:is(state)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).options">FSM.options</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(FSM).subs">FSM.subs</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -1101,6 +1161,20 @@ The To state.</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).CallScheduler" >
|
||||
<strong>FSM.CallScheduler</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -1115,6 +1189,20 @@ The To state.</p>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).Events" >
|
||||
<strong>FSM.Events</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -1315,6 +1403,20 @@ A string containing the start state.</p>
|
||||
<p><em><a href="##(FSM)">#FSM</a>:</em></p>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).Scores" >
|
||||
<strong>FSM.Scores</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -1343,6 +1445,48 @@ A string defining the start state.</p>
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM)._EndStates" >
|
||||
<strong>FSM._EndStates</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM)._Processes" >
|
||||
<strong>FSM._Processes</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM)._Scores" >
|
||||
<strong>FSM._Scores</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em>#string</em>
|
||||
<a id="#(FSM)._StartState" >
|
||||
<strong>FSM._StartState</strong>
|
||||
</a>
|
||||
@ -1351,6 +1495,20 @@ A string defining the start state.</p>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM)._Transitions" >
|
||||
<strong>FSM._Transitions</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -1622,7 +1780,6 @@ A string defining the start state.</p>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).current" >
|
||||
<strong>FSM.current</strong>
|
||||
</a>
|
||||
@ -1631,6 +1788,20 @@ A string defining the start state.</p>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).endstates" >
|
||||
<strong>FSM.endstates</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
@ -1652,6 +1823,33 @@ A string defining the start state.</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<a id="#(FSM).options" >
|
||||
<strong>FSM.options</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em></em>
|
||||
<a id="#(FSM).subs" >
|
||||
<strong>FSM.subs</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
@ -138,7 +138,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(OBJECT).New">OBJECT:New(ObjectName)</a></td>
|
||||
<td class="name" nowrap="nowrap"><a href="##(OBJECT).New">OBJECT:New(ObjectName, Test)</a></td>
|
||||
<td class="summary">
|
||||
<p>Create a new OBJECT from a DCSObject</p>
|
||||
</td>
|
||||
@ -256,20 +256,25 @@ The DCS Object is not existing or alive. </p>
|
||||
<dt>
|
||||
|
||||
<a id="#(OBJECT).New" >
|
||||
<strong>OBJECT:New(ObjectName)</strong>
|
||||
<strong>OBJECT:New(ObjectName, Test)</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<p>Create a new OBJECT from a DCSObject</p>
|
||||
|
||||
<h3>Parameter</h3>
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<p><code><em><a href="Dcs.DCSWrapper.Object.html##(Object)">Dcs.DCSWrapper.Object#Object</a> ObjectName </em></code>:
|
||||
The Object name</p>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<p><code><em> Test </em></code>: </p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Return value</h3>
|
||||
|
||||
@ -470,6 +470,12 @@ The following iterator methods are currently available within the SET</em>AIRBAS
|
||||
<td class="name" nowrap="nowrap"><a href="##(SET_BASE).AddObject">SET_BASE:AddObject(Object)</a></td>
|
||||
<td class="summary">
|
||||
<p>Adds a <a href="Core.Base.html##(BASE)">Core.Base#BASE</a> object in the <a href="Core.Set.html##(SET_BASE)">Core.Set#SET_BASE</a>, using the Object Name as the index.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="##(SET_BASE).CallScheduler">SET_BASE.CallScheduler</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -1600,6 +1606,20 @@ The added BASE Object.</p>
|
||||
<p><em><a href="Core.Base.html##(BASE)">Core.Base#BASE</a>:</em>
|
||||
The added BASE Object.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
|
||||
<em><a href="Core.Scheduler.html##(SCHEDULER)">Core.Scheduler#SCHEDULER</a></em>
|
||||
<a id="#(SET_BASE).CallScheduler" >
|
||||
<strong>SET_BASE.CallScheduler</strong>
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
|
||||
@ -1692,6 +1692,9 @@ The group that was spawned. You can use this group for further actions.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="function">
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
<tr>
|
||||
<td class="name" nowrap="nowrap"><a href="AI_Balancer.html">AI_Balancer</a></td>
|
||||
<td class="summary">
|
||||
<p>This module contains the AI_BALANCER class.</p>
|
||||
<p>SP:N MP:Y AI:Y HU:N TYP:A -- This module contains the AI_BALANCER class.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
BIN
docs/Presentations/AI_Balancer/AI_BALANCER.pptx
Normal file
BIN
docs/Presentations/AI_Balancer/AI_BALANCER.pptx
Normal file
Binary file not shown.
BIN
docs/Presentations/AI_Balancer/Dia1.JPG
Normal file
BIN
docs/Presentations/AI_Balancer/Dia1.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
BIN
docs/Presentations/AI_Balancer/Dia2.JPG
Normal file
BIN
docs/Presentations/AI_Balancer/Dia2.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
Loading…
x
Reference in New Issue
Block a user