New File Structure Updates

This commit is contained in:
FlightControl
2016-12-06 10:17:21 +01:00
parent 931464dfec
commit dd162831fa
62 changed files with 1317 additions and 1291 deletions

View File

@@ -0,0 +1,261 @@
--- (SP) (MP) (FSM) Account for (Detect, count and report) DCS events occuring on DCS objects (units).
--
-- ===
--
-- # @{#PROCESS_ACCOUNT} FSM class, extends @{Process#PROCESS}
--
-- ## PROCESS_ACCOUNT state machine:
--
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below.
-- Each derived class follows exactly the same process, using the same events and following the same state transitions,
-- but will have **different implementation behaviour** upon each event or state transition.
--
-- ### PROCESS_ACCOUNT **Events**:
--
-- These are the events defined in this class:
--
-- * **Start**: The process is started. The process will go into the Report state.
-- * **Event**: A relevant event has occured that needs to be accounted for. The process will go into the Account state.
-- * **Report**: The process is reporting to the player the accounting status of the DCS events.
-- * **More**: There are more DCS events that need to be accounted for. The process will go back into the Report state.
-- * **NoMore**: There are no more DCS events that need to be accounted for. The process will go into the Success state.
--
-- ### PROCESS_ACCOUNT **Event methods**:
--
-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process.
-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine:
--
-- * **Immediate**: The event method has exactly the name of the event.
-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed.
--
-- ### PROCESS_ACCOUNT **States**:
--
-- * **Assigned**: The player is assigned to the task. This is the initialization state for the process.
-- * **Waiting**: the process is waiting for a DCS event to occur within the simulator. This state is set automatically.
-- * **Report**: The process is Reporting to the players in the group of the unit. This state is set automatically every 30 seconds.
-- * **Account**: The relevant DCS event has occurred, and is accounted for.
-- * **Success (*)**: All DCS events were accounted for.
-- * **Failed (*)**: The process has failed.
--
-- (*) End states of the process.
--
-- ### PROCESS_ACCOUNT state transition methods:
--
-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
-- There are 2 moments when state transition methods will be called by the state machine:
--
-- * **Before** the state transition.
-- The state transition method needs to start with the name **OnBefore + the name of the state**.
-- If the state transition method returns false, then the processing of the state transition will not be done!
-- If you want to change the behaviour of the AIControllable at this event, return false,
-- but then you'll need to specify your own logic using the AIControllable!
--
-- * **After** the state transition.
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
-- These state transition methods need to provide a return value, which is specified at the function description.
--
-- # 1) @{#PROCESS_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#PROCESS_ACCOUNT}
--
-- The PROCESS_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
-- The process is given a @{Set} of units that will be tracked upon successful destruction.
-- The process will end after each target has been successfully destroyed.
-- Each successful dead will trigger an Account state transition that can be scored, modified or administered.
--
--
-- ## PROCESS_ACCOUNT_DEADS constructor:
--
-- * @{#PROCESS_ACCOUNT_DEADS.New}(): Creates a new PROCESS_ACCOUNT_DEADS object.
--
-- ===
--
-- @module Account
do -- PROCESS_ACCOUNT
--- PROCESS_ACCOUNT class
-- @type PROCESS_ACCOUNT
-- @field Set#SET_UNIT TargetSetUnit
-- @extends Core.StateMachine#FSM_TEMPLATE
PROCESS_ACCOUNT = {
ClassName = "PROCESS_ACCOUNT",
TargetSetUnit = nil,
}
--- Creates a new DESTROY process.
-- @param #PROCESS_ACCOUNT self
-- @return #PROCESS_ACCOUNT
function PROCESS_ACCOUNT:New()
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_TEMPLATE:New( "PROCESS_ACCOUNT" ) ) -- Core.StateMachine#FSM_TEMPLATE
self:AddTransition( "Assigned", "Start", "Waiting")
self:AddTransition( "*", "Wait", "Waiting")
self:AddTransition( "*", "Report", "Report")
self:AddTransition( "*", "Event", "Account")
self:AddTransition( "Account", "More", "Wait")
self:AddTransition( "Account", "NoMore", "Accounted")
self:AddTransition( "*", "Fail", "Failed")
self:AddEndState( "Accounted" )
self:AddEndState( "Failed" )
self:SetStartState( "Assigned" )
return self
end
--- Process Events
--- StateMachine callback function
-- @param #PROCESS_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT:onafterStart( ProcessUnit, Event, From, To )
self:EventOnDead( self.onfuncEventDead )
self:__Wait( 1 )
end
--- StateMachine callback function
-- @param #PROCESS_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT:onenterWaiting( ProcessUnit, Event, From, To )
if self.DisplayCount >= self.DisplayInterval then
self:Report()
self.DisplayCount = 1
else
self.DisplayCount = self.DisplayCount + 1
end
return true -- Process always the event.
end
--- StateMachine callback function
-- @param #PROCESS_ACCOUNT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT:onafterEvent( ProcessUnit, Event, From, To, Event )
self:__NoMore( 1 )
end
end -- PROCESS_ACCOUNT
do -- PROCESS_ACCOUNT_DEADS
--- PROCESS_ACCOUNT_DEADS class
-- @type PROCESS_ACCOUNT_DEADS
-- @field Set#SET_UNIT TargetSetUnit
-- @extends #PROCESS_ACCOUNT
PROCESS_ACCOUNT_DEADS = {
ClassName = "PROCESS_ACCOUNT_DEADS",
TargetSetUnit = nil,
}
--- Creates a new DESTROY process.
-- @param #PROCESS_ACCOUNT_DEADS self
-- @param Set#SET_UNIT TargetSetUnit
-- @param #string TaskName
function PROCESS_ACCOUNT_DEADS:New( TargetSetUnit, TaskName )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS_ACCOUNT:New() ) -- #PROCESS_ACCOUNT_DEADS
self:SetParameters( {
TargetSetUnit = TargetSetUnit,
TaskName = TaskName,
DisplayInterval = 30,
DisplayCount = 30,
DisplayMessage = true,
DisplayTime = 10, -- 10 seconds is the default
DisplayCategory = "HQ", -- Targets is the default display category
} )
return self
end
function PROCESS_ACCOUNT_DEADS:_Destructor()
self:E("_Destructor")
self:EventRemoveAll()
end
--- Process Events
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT_DEADS:onenterReport( ProcessUnit, Event, From, To )
self:E( { ProcessUnit, Event, From, To } )
local TaskGroup = ProcessUnit:GetGroup()
MESSAGE:New( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup )
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT_DEADS:onenterAccount( ProcessUnit, Event, From, To, EventData )
self:T( { ProcessUnit, EventData, Event, From, To } )
self:T({self.Controllable})
self.TargetSetUnit:Flush()
if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
local TaskGroup = ProcessUnit:GetGroup()
self.TargetSetUnit:RemoveUnitsByName( EventData.IniUnitName )
MESSAGE:New( "You hit a target. Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup )
end
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Event, From, To, EventData )
if self.TargetSetUnit:Count() > 0 then
self:__More( 1 )
else
self:__NoMore( 1 )
end
end
--- DCS Events
--- @param #PROCESS_ACCOUNT_DEADS self
-- @param Event#EVENTDATA EventData
function PROCESS_ACCOUNT_DEADS:onfuncEventDead( EventData )
self:T( { "EventDead", EventData } )
if EventData.IniDCSUnit then
self:__Event( 1, EventData )
end
end
end -- PROCESS_ACCOUNT DEADS

View File

@@ -0,0 +1,284 @@
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
--
-- ===
--
-- # @{#PROCESS_ASSIGN} FSM class, extends @{Process#PROCESS}
--
-- ## PROCESS_ASSIGN state machine:
--
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below.
-- Each derived class follows exactly the same process, using the same events and following the same state transitions,
-- but will have **different implementation behaviour** upon each event or state transition.
--
-- ### PROCESS_ASSIGN **Events**:
--
-- These are the events defined in this class:
--
-- * **Start**: Start the tasking acceptance process.
-- * **Assign**: Assign the task.
-- * **Reject**: Reject the task..
--
-- ### PROCESS_ASSIGN **Event methods**:
--
-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process.
-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine:
--
-- * **Immediate**: The event method has exactly the name of the event.
-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed.
--
-- ### PROCESS_ASSIGN **States**:
--
-- * **UnAssigned**: The player has not accepted the task.
-- * **Assigned (*)**: The player has accepted the task.
-- * **Rejected (*)**: The player has not accepted the task.
-- * **Waiting**: The process is awaiting player feedback.
-- * **Failed (*)**: The process has failed.
--
-- (*) End states of the process.
--
-- ### PROCESS_ASSIGN state transition methods:
--
-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
-- There are 2 moments when state transition methods will be called by the state machine:
--
-- * **Before** the state transition.
-- The state transition method needs to start with the name **OnBefore + the name of the state**.
-- If the state transition method returns false, then the processing of the state transition will not be done!
-- If you want to change the behaviour of the AIControllable at this event, return false,
-- but then you'll need to specify your own logic using the AIControllable!
--
-- * **After** the state transition.
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
-- These state transition methods need to provide a return value, which is specified at the function description.
--
-- ===
--
-- # 1) @{#PROCESS_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#PROCESS_ASSIGN}
--
-- The PROCESS_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
--
-- ## 1.1) PROCESS_ASSIGN_ACCEPT constructor:
--
-- * @{#PROCESS_ASSIGN_ACCEPT.New}(): Creates a new PROCESS_ASSIGN_ACCEPT object.
--
-- ===
--
-- # 2) @{#PROCESS_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#PROCESS_ASSIGN}
--
-- The PROCESS_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option.
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
-- The assignment type also allows to reject the task.
--
-- ## 2.1) PROCESS_ASSIGN_MENU_ACCEPT constructor:
-- -----------------------------------------
--
-- * @{#PROCESS_ASSIGN_MENU_ACCEPT.New}(): Creates a new PROCESS_ASSIGN_MENU_ACCEPT object.
--
-- ===
--
-- @module Assign
do -- PROCESS_ASSIGN
--- PROCESS_ASSIGN class
-- @type PROCESS_ASSIGN
-- @field Tasking.Task#TASK_BASE Task
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends Core.StateMachine#FSM_TEMPLATE
PROCESS_ASSIGN = {
ClassName = "PROCESS_ASSIGN",
}
--- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted.
-- @param #PROCESS_ASSIGN self
-- @return #PROCESS_ASSIGN The task acceptance process.
function PROCESS_ASSIGN:New()
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_TEMPLATE:New( "PROCESS_ASSIGN" ) ) -- Core.StateMachine#FSM_TEMPLATE
self:AddTransition( "UnAssigned", "Start", "Waiting" )
self:AddTransition( "Waiting", "Assign", "Assigned" )
self:AddTransition( "Waiting", "Reject", "Rejected" )
self:AddTransition( "*", "Fail", "Failed" )
self:AddEndState( "Assigned" )
self:AddEndState( "Rejected" )
self:AddEndState( "Failed" )
self:SetStartState( "UnAssigned" )
return self
end
end -- PROCESS_ASSIGN
do -- PROCESS_ASSIGN_ACCEPT
--- PROCESS_ASSIGN_ACCEPT class
-- @type PROCESS_ASSIGN_ACCEPT
-- @field Tasking.Task#TASK_BASE Task
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends Fsm.Process#PROCESS
PROCESS_ASSIGN_ACCEPT = {
ClassName = "PROCESS_ASSIGN_ACCEPT",
}
--- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted.
-- @param #PROCESS_ASSIGN_ACCEPT self
-- @param #string TaskBriefing
function PROCESS_ASSIGN_ACCEPT:New( TaskBriefing )
local self = BASE:Inherit( self, PROCESS_ASSIGN:New() ) -- #PROCESS_ASSIGN_ACCEPT
self:SetParameters( { TaskBriefing = TaskBriefing } )
return self
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN_ACCEPT:onafterStart( ProcessUnit, Event, From, To )
self:E( { ProcessUnit, Event, From, To } )
local ProcessGroup = ProcessUnit:GetGroup()
MESSAGE:New( self.TaskBriefing, 30, ProcessUnit:GetPlayerName() .. " Task Acceptance" ):ToGroup( ProcessGroup )
self:__Assign( 1 )
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, Event, From, To )
env.info( "in here" )
self:E( { ProcessUnit, Event, From, To } )
local ProcessGroup = ProcessUnit:GetGroup()
MESSAGE:New( "You are assigned to the task " .. self.Task:GetName(), 30, ProcessUnit:GetPlayerName() .. ": Task Assignment" ):ToGroup( ProcessGroup )
self.Task:Assign()
end
end -- PROCESS_ASSIGN_ACCEPT
do -- PROCESS_ASSIGN_MENU_ACCEPT
--- PROCESS_ASSIGN_MENU_ACCEPT class
-- @type PROCESS_ASSIGN_MENU_ACCEPT
-- @field Tasking.Task#TASK_BASE Task
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends #PROCESS_ASSIGN
PROCESS_ASSIGN_MENU_ACCEPT = {
ClassName = "PROCESS_ASSIGN_MENU_ACCEPT",
}
--- Init.
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param #string TaskName
-- @param #string TaskBriefing
-- @return #PROCESS_ASSIGN_MENU_ACCEPT self
function PROCESS_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS_ASSIGN:New() ) -- #PROCESS_ASSIGN_MENU_ACCEPT
self:SetParameters( { TaskName = TaskName, TaskBriefing = TaskBriefing } )
return self
end
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param #string TaskName
-- @param #string TaskBriefing
-- @return #PROCESS_ASSIGN_MENU_ACCEPT self
function PROCESS_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing )
self.TaskBriefing = TaskBriefing
self.TaskName = TaskName
return self
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, Event, From, To )
self:E( { ProcessUnit, Event, From, To } )
MESSAGE:New( self.TaskBriefing .. "\nAccess the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", 30, "Task Assignment" ):ToGroup( ProcessUnit:GetGroup() )
local ProcessGroup = ProcessUnit:GetGroup()
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" )
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self )
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self )
end
--- Menu function.
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
function PROCESS_ASSIGN_MENU_ACCEPT:MenuAssign()
self:E( )
self:__Assign( 1 )
end
--- Menu function.
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
function PROCESS_ASSIGN_MENU_ACCEPT:MenuReject()
self:E( )
self:__Reject( 1 )
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Event, From, To )
self:E( { ProcessUnit.UnitNameEvent, From, To } )
self.Menu:Remove()
end
--- StateMachine callback function
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, Event, From, To )
self:E( { ProcessUnit.UnitName, Event, From, To } )
self.Menu:Remove()
--TODO: need to resolve this problem ... it has to do with the events ...
--self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event
ProcessUnit:Destroy()
end
end -- PROCESS_ASSIGN_MENU_ACCEPT

View File

@@ -12,7 +12,7 @@
--
-- * CARGO_GROUPED, represented by a Group of CARGO_UNITs.
--
-- 1) @{Cargo#CARGO_BASE} class, extends @{StateMachine#STATEMACHINE_PROCESS}
-- 1) @{Fsm.Cargo#CARGO_BASE} class, extends @{Fsm.Fsm#FSM_PROCESS}
-- ==========================================================================
-- The @{#CARGO_BASE} class defines the core functions that defines a cargo object within MOOSE.
-- A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
@@ -74,14 +74,14 @@
-- The cargo must be in the **UnLoaded** state.
-- @function [parent=#CARGO_BASE] Board
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
--- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier.
-- The cargo must be in the **UnLoaded** state.
-- @function [parent=#CARGO_BASE] __Board
-- @param #CARGO_BASE self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- UnBoard
@@ -90,14 +90,14 @@
-- The cargo must be in the **Loaded** state.
-- @function [parent=#CARGO_BASE] UnBoard
-- @param #CARGO_BASE self
-- @param Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
-- The cargo must be in the **Loaded** state.
-- @function [parent=#CARGO_BASE] __UnBoard
-- @param #CARGO_BASE self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
-- Load
@@ -106,14 +106,14 @@
-- The cargo must be in the **UnLoaded** state.
-- @function [parent=#CARGO_BASE] Load
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
--- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **UnLoaded** state.
-- @function [parent=#CARGO_BASE] __Load
-- @param #CARGO_BASE self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo.
-- UnLoad
@@ -122,14 +122,14 @@
-- The cargo must be in the **Loaded** state.
-- @function [parent=#CARGO_BASE] UnLoad
-- @param #CARGO_BASE self
-- @param Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
-- The cargo must be in the **Loaded** state.
-- @function [parent=#CARGO_BASE] __UnLoad
-- @param #CARGO_BASE self
-- @param #number DelaySeconds The amount of seconds to delay the action.
-- @param Point#POINT_VEC2 ToPointVec2 (optional) @{Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
-- State Transition Functions
@@ -137,62 +137,62 @@
--- @function [parent=#CARGO_BASE] OnBeforeUnLoaded
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
--- @function [parent=#CARGO_BASE] OnAfterUnLoaded
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- Loaded
--- @function [parent=#CARGO_BASE] OnBeforeLoaded
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
--- @function [parent=#CARGO_BASE] OnAfterLoaded
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- Boarding
--- @function [parent=#CARGO_BASE] OnBeforeBoarding
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
--- @function [parent=#CARGO_BASE] OnAfterBoarding
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- UnBoarding
--- @function [parent=#CARGO_BASE] OnBeforeUnBoarding
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
--- @function [parent=#CARGO_BASE] OnAfterUnBoarding
-- @param #CARGO_BASE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- TODO: Find all Carrier objects and make the type of the Carriers Unit#UNIT in the documentation.
-- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation.
CARGOS = {}
do -- CARGO_BASE
--- @type CARGO_BASE
-- @extends StateMachine#STATEMACHINE_PROCESS
-- @extends Fsm.Fsm#FSM_PROCESS
-- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers.
-- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo.
-- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg.
-- @field #number ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier.
-- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded.
-- @field Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere...
-- @field Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere...
-- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere...
-- @field Wrapper.Controllable#CONTROLLABLE CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere...
-- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded.
-- @field #boolean Moveable This flag defines if the cargo is moveable.
-- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit.
@@ -211,7 +211,7 @@ do -- CARGO_BASE
}
--- @type CARGO_BASE.CargoObjects
-- @map < #string, Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
--- CARGO_BASE Constructor. This class is an abstract class and should not be instantiated.
@@ -238,7 +238,7 @@ function CARGO_BASE:New( Type, Name, Weight, ReportRadius, NearRadius )
},
}
local self = BASE:Inherit( self, STATEMACHINE_PROCESS:New( FSMT ) ) -- #CARGO_BASE
local self = BASE:Inherit( self, FSM_PROCESS:New( FSMT ) ) -- #CARGO_BASE
self:F( { Type, Name, Weight, ReportRadius, NearRadius } )
@@ -274,7 +274,7 @@ end
--- Check if CargoCarrier is near the Cargo to be Loaded.
-- @param #CARGO_BASE self
-- @param Point#POINT_VEC2 PointVec2
-- @param Core.Point#POINT_VEC2 PointVec2
-- @return #boolean
function CARGO_BASE:IsNear( PointVec2 )
self:F( { PointVec2 } )
@@ -301,7 +301,7 @@ do -- CARGO_REPRESENTABLE
--- CARGO_REPRESENTABLE Constructor.
-- @param #CARGO_REPRESENTABLE self
-- @param Controllable#Controllable CargoObject
-- @param Wrapper.Controllable#Controllable CargoObject
-- @param #string Type
-- @param #string Name
-- @param #number Weight
@@ -320,7 +320,7 @@ end
--- Route a cargo unit to a PointVec2.
-- @param #CARGO_REPRESENTABLE self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number Speed
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
@@ -350,7 +350,7 @@ do -- CARGO_UNIT
--- CARGO_UNIT Constructor.
-- @param #CARGO_UNIT self
-- @param Unit#UNIT CargoUnit
-- @param Wrapper.Unit#UNIT CargoUnit
-- @param #string Type
-- @param #string Name
-- @param #number Weight
@@ -371,7 +371,7 @@ end
--- Enter UnBoarding State.
-- @param #CARGO_UNIT self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -416,7 +416,7 @@ end
--- Leave UnBoarding State.
-- @param #CARGO_UNIT self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -440,7 +440,7 @@ end
--- UnBoard Event.
-- @param #CARGO_UNIT self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -465,7 +465,7 @@ end
--- Enter UnLoaded State.
-- @param #CARGO_UNIT self
-- @param Point#POINT_VEC2
-- @param Core.Point#POINT_VEC2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -503,7 +503,7 @@ end
--- Enter Boarding State.
-- @param #CARGO_UNIT self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -535,7 +535,7 @@ end
--- Leave Boarding State.
-- @param #CARGO_UNIT self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -553,7 +553,7 @@ end
--- Loaded State.
-- @param #CARGO_UNIT self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -602,7 +602,7 @@ do -- CARGO_PACKAGE
--- CARGO_PACKAGE Constructor.
-- @param #CARGO_PACKAGE self
-- @param Unit#UNIT CargoCarrier The UNIT carrying the package.
-- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package.
-- @param #string Type
-- @param #string Name
-- @param #number Weight
@@ -621,11 +621,11 @@ end
--- Board Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
-- @param #number BoardDistance
-- @param #number Angle
@@ -660,7 +660,7 @@ end
--- Check if CargoCarrier is near the Cargo to be Loaded.
-- @param #CARGO_PACKAGE self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @return #boolean
function CARGO_PACKAGE:IsNear( CargoCarrier )
self:F()
@@ -679,11 +679,11 @@ end
--- Boarded Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_PACKAGE:onafterOnBoarded( FsmP, Event, From, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F()
@@ -696,7 +696,7 @@ end
--- UnBoard Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -739,11 +739,11 @@ end
--- UnBoarded Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_PACKAGE:onafterUnBoarded( FsmP, Event, From, To, CargoCarrier, Speed )
self:F()
@@ -756,11 +756,11 @@ end
--- Load Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
-- @param #number LoadDistance
-- @param #number Angle
@@ -785,7 +785,7 @@ end
--- UnLoad Event.
-- @param #CARGO_PACKAGE self
-- @param StateMachine#STATEMACHINE_PROCESS FsmP
-- @param Fsm.Fsm#FSM_PROCESS FsmP
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -816,7 +816,7 @@ end
do -- CARGO_GROUP
--- @type CARGO_GROUP
-- @extends Cargo#CARGO_BASE
-- @extends Fsm.Cargo#CARGO_BASE
-- @field Set#SET_BASE CargoSet A set of cargo objects.
-- @field #string Name A string defining the name of the cargo group. The name is the unique identifier of the cargo.
CARGO_GROUP = {
@@ -825,7 +825,7 @@ do -- CARGO_GROUP
--- CARGO_GROUP constructor.
-- @param #CARGO_GROUP self
-- @param Set#Set_BASE CargoSet
-- @param Core.Set#Set_BASE CargoSet
-- @param #string Type
-- @param #string Name
-- @param #number Weight
@@ -847,14 +847,14 @@ end -- CARGO_GROUP
do -- CARGO_GROUPED
--- @type CARGO_GROUPED
-- @extends Cargo#CARGO_GROUP
-- @extends Fsm.Cargo#CARGO_GROUP
CARGO_GROUPED = {
ClassName = "CARGO_GROUPED",
}
--- CARGO_GROUPED constructor.
-- @param #CARGO_GROUPED self
-- @param Set#Set_BASE CargoSet
-- @param Core.Set#Set_BASE CargoSet
-- @param #string Type
-- @param #string Name
-- @param #number Weight
@@ -870,7 +870,7 @@ end
--- Enter Boarding State.
-- @param #CARGO_GROUPED self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -893,7 +893,7 @@ end
--- Enter Loaded State.
-- @param #CARGO_GROUPED self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -910,7 +910,7 @@ end
--- Leave Boarding State.
-- @param #CARGO_GROUPED self
-- @param Unit#UNIT CargoCarrier
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -937,7 +937,7 @@ end
--- Enter UnBoarding State.
-- @param #CARGO_GROUPED self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -963,7 +963,7 @@ end
--- Leave UnBoarding State.
-- @param #CARGO_GROUPED self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -998,7 +998,7 @@ end
--- UnBoard Event.
-- @param #CARGO_GROUPED self
-- @param Point#POINT_VEC2 ToPointVec2
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -1012,7 +1012,7 @@ end
--- Enter UnLoaded State.
-- @param #CARGO_GROUPED self
-- @param Point#POINT_VEC2
-- @param Core.Point#POINT_VEC2
-- @param #string Event
-- @param #string From
-- @param #string To

View File

@@ -0,0 +1,785 @@
--- This module contains the FSM class.
-- 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 to make the state machine hierarchical...
-- It is a fantastic development, this module.
--
-- ===
--
-- 1) @{Workflow#FSM} class, extends @{Core.Base#BASE}
-- ==============================================
--
-- 1.1) Add or remove objects from the FSM
-- --------------------------------------------
-- @module StateMachine
-- @author FlightControl
--- FSM class
-- @type FSM
-- @extends Core.Base#BASE
FSM = {
ClassName = "FSM",
}
--- Creates a new FSM object.
-- @param #FSM self
-- @return #FSM
function FSM:New( FsmT )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
--assert(options.events)
--local MT = {}
--setmetatable( self, MT )
--self.__index = self
self.options = options or {}
self.options.subs = self.options.subs or {}
self.current = self.options.initial or 'none'
self.events = {}
self.subs = {}
self.endstates = {}
self.Scores = {}
FsmT = FsmT or FSM_TEMPLATE:New( "" )
self:SetStartState( FsmT:GetStartState() )
for TransitionID, Transition in pairs( FsmT:GetTransitions() ) do
self:AddTransition( Transition.From, Transition.Event, Transition.To )
end
self:CopyCallHandlers( FsmT )
return self
end
function FSM:AddTransition( From, Event, To )
local event = {}
event.from = From
event.name = Event
event.to = To
self:E( event )
self:_eventmap( self.events, event )
end
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task.
-- @return Process#PROCESS
function FSM:AddProcess( From, Event, Process, ReturnEvents )
local sub = {}
sub.FromParent = From
sub.EventParent = Event
sub.fsm = Process
sub.event = "Start"
sub.ReturnEvents = ReturnEvents
self:_submap( self.subs, sub, nil )
self:AddTransition( From, Event, From )
return Process
end
function FSM:AddEndState( State )
self.endstates[State] = State
end
function FSM:SetStartState( State )
self.current = State
end
function FSM:GetSubs()
return self.options.subs
end
function FSM:LoadCallBacks( CallBackTable )
for name, callback in pairs( CallBackTable or {} ) do
self[name] = callback
end
end
function FSM:_eventmap( events, event )
local name = event.name
local __name = "__" .. event.name
self[name] = self[name] or self:_create_transition(name)
self[__name] = self[__name] or self:_delayed_transition(name)
self:T( "Added methods: " .. name .. ", " .. __name )
events[name] = self.events[name] or { map = {} }
self:_add_to_map( events[name].map, event )
end
function FSM:_submap( subs, sub, name )
self:F( { sub = sub, name = name } )
subs[sub.FromParent] = subs[sub.FromParent] or {}
subs[sub.FromParent][sub.EventParent] = subs[sub.FromParent][sub.EventParent] or {}
-- Make the reference table weak.
-- setmetatable( subs[sub.FromParent][sub.EventParent], { __mode = "k" } )
subs[sub.FromParent][sub.EventParent][sub] = {}
subs[sub.FromParent][sub.EventParent][sub].fsm = sub.fsm
subs[sub.FromParent][sub.EventParent][sub].event = sub.event
subs[sub.FromParent][sub.EventParent][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop.
subs[sub.FromParent][sub.EventParent][sub].name = name
subs[sub.FromParent][sub.EventParent][sub].fsmparent = self
end
function FSM:_call_handler(handler, params)
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, unpack(params) )
end
end
function FSM._handler( self, EventName, ... )
self:E( { EventName, ... } )
local can, to = self:can( EventName )
self:E( { EventName, self.current, can, to } )
local ReturnValues = nil
if can then
local from = self.current
local params = { EventName, from, to, ... }
if self:_call_handler("onbefore" .. EventName, params) == false
or self:_call_handler("onleave" .. from, params) == false then
return false
end
self.current = to
local execute = true
local subtable = self:_gosub( from, EventName )
for _, sub in pairs( subtable ) do
--if sub.nextevent then
-- self:F2( "nextevent = " .. sub.nextevent )
-- self[sub.nextevent]( self )
--end
self:E( "calling sub event: " .. sub.event )
sub.fsm.fsmparent = self
sub.fsm.ReturnEvents = sub.ReturnEvents
sub.fsm[sub.event]( sub.fsm )
execute = true
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("onafter" .. EventName, params)
self:_call_handler("onstatechange", params)
fsmparent[event]( fsmparent )
execute = false
end
if execute then
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
if from ~= to then
self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } )
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" .. to, callback = self["OnAfter" .. to] } )
ReturnValues = self:_call_handler("OnAfter" .. to, params )
end
self:_call_handler("onstatechange", params)
end
return ReturnValues
end
return nil
end
function FSM:_delayed_transition( EventName )
self:E( { EventName = EventName } )
return function( self, DelaySeconds, ... )
self:T( "Delayed Event: " .. EventName )
SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds )
end
end
function FSM:_create_transition( EventName )
self:E( { Event = EventName } )
return function( self, ... ) return self._handler( self, EventName , ... ) end
end
function FSM:_gosub( ParentFrom, ParentEvent )
local fsmtable = {}
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } )
return self.subs[ParentFrom][ParentEvent]
else
return {}
end
end
function FSM:_isendstate( Current )
local FSMParent = self.fsmparent
if FSMParent and self.endstates[Current] then
self:E( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
FSMParent.current = Current
local ParentFrom = FSMParent.current
self:E( ParentFrom )
self:E( self.ReturnEvents )
local Event = self.ReturnEvents[Current]
self:E( { ParentFrom, Event, self.ReturnEvents } )
if Event then
return FSMParent, Event
else
self:E( { "Could not find parent event name for state ", ParentFrom } )
end
end
return nil
end
function FSM:_add_to_map(map, event)
self:F3( { map, event } )
if type(event.from) == 'string' then
map[event.from] = event.to
else
for _, from in ipairs(event.from) do
map[from] = event.to
end
end
self:T3( { map, event } )
end
function FSM:GetState()
return self.current
end
function FSM:Is( State )
return self.current == State
end
function FSM:is(state)
return self.current == state
end
function FSM:can(e)
local event = self.events[e]
self:F3( { self.current, event } )
local to = event and event.map[self.current] or event.map['*']
return to ~= nil, to
end
function FSM:cannot(e)
return not self:can(e)
end
function FSM:CopyCallHandlers( FsmT )
local Parent = BASE:GetParent( FsmT )
if Parent then
self:CopyCallHandlers( Parent )
end
for ElementID, Element in pairs( FsmT ) do
self:E( { ElementID = ElementID } )
if type( Element ) == "function" then
if ElementID.find( ElementID, "^onbefore" ) or
ElementID.find( ElementID, "^onafter" ) or
ElementID.find( ElementID, "^onenter" ) or
ElementID.find( ElementID, "^onleave" ) or
ElementID.find( ElementID, "^onfunc" ) then
self[ ElementID ] = Element
end
end
end
end
function FSM:todot(filename)
local dotfile = io.open(filename,'w')
dotfile:write('digraph {\n')
local transition = function(event,from,to)
dotfile:write(string.format('%s -> %s [label=%s];\n',from,to,event))
end
for _, event in pairs(self.options.events) do
if type(event.from) == 'table' then
for _, from in ipairs(event.from) do
transition(event.name,from,event.to)
end
else
transition(event.name,event.from,event.to)
end
end
dotfile:write('}\n')
dotfile:close()
end
--- STATEMACHINE_CONTROLLABLE class
-- @type STATEMACHINE_CONTROLLABLE
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
-- @extends Core.StateMachine#FSM
STATEMACHINE_CONTROLLABLE = {
ClassName = "STATEMACHINE_CONTROLLABLE",
}
--- Creates a new STATEMACHINE_CONTROLLABLE object.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @param #table FSMT Finite State Machine Table
-- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @return #STATEMACHINE_CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:New( FSMT, Controllable )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Fsm.Fsm#STATEMACHINE_CONTROLLABLE
if Controllable then
self:SetControllable( Controllable )
end
return self
end
--- Sets the CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @param Wrapper.Controllable#CONTROLLABLE FSMControllable
-- @return #STATEMACHINE_CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:SetControllable( FSMControllable )
self:F( FSMControllable )
self.Controllable = FSMControllable
end
--- Gets the CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @return Wrapper.Controllable#CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:GetControllable()
return self.Controllable
end
function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params )
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
end
if self[handler] then
self:E( "Calling " .. handler )
return xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler )
--return self[handler]( self, self.Controllable, unpack( params ) )
end
end
--- FSM_PROCESS class
-- @type FSM_PROCESS
-- @field Process#PROCESS Process
-- @field Tasking.Task#TASK_BASE Task
-- @extends Core.StateMachine#STATEMACHINE_CONTROLLABLE
FSM_PROCESS = {
ClassName = "FSM_PROCESS",
}
--- Creates a new FSM_PROCESS object.
-- @param #FSM_PROCESS self
-- @return #FSM_PROCESS
function FSM_PROCESS:New( FsmT, Controllable, Task )
local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FsmT ) ) -- Fsm.Fsm#FSM_PROCESS
self:Assign( Controllable, Task )
self.ClassName = FsmT._Name
for ParameterID, Parameter in pairs( FsmT:GetParameters() ) do
self[ ParameterID ] = Parameter
end
for ProcessID, Process in pairs( FsmT:GetProcesses() ) do
self:E( Process )
local FsmProcess = self:AddProcess(Process.From, Process.Event, FSM_PROCESS:New( Process.Process, Controllable, Task ), Process.ReturnEvents )
end
for EndStateID, EndState in pairs( FsmT:GetEndStates() ) do
self:E( EndState )
self:AddEndState( EndState )
end
-- Copy the score tables
for ScoreID, Score in pairs( FsmT:GetScores() ) do
self:E( Score )
self:AddScore( ScoreID,Score.ScoreText,Score.Score )
end
return self
end
--- Sets the task of the process.
-- @param #PROCESS self
-- @param Tasking.Task#TASK_BASE Task
-- @return #PROCESS
function FSM_PROCESS:SetTask( Task )
self.Task = Task
return self
end
--- Gets the task of the process.
-- @param #PROCESS self
-- @return Tasking.Task#TASK_BASE
function FSM_PROCESS:GetTask()
return self.Task
end
--- Gets the mission of the process.
-- @param #PROCESS self
-- @return Tasking.Mission#MISSION
function FSM_PROCESS:GetMission()
return self.Task.Mission
end
--- Assign the process to a @{Unit} and activate the process.
-- @param #FSM_PROCESS self
-- @param Task.Tasking#TASK_BASE Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @return #FSM_PROCESS self
function FSM_PROCESS:Assign( ProcessUnit, Task )
self:E( { Task, ProcessUnit } )
self:SetControllable( ProcessUnit )
self:SetTask( Task )
--self.ProcessGroup = ProcessUnit:GetGroup()
return self
end
--- Adds a score for the FSM_PROCESS to be achieved.
-- @param #FSM_PROCESS self
-- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #FSM_PROCESS self
function FSM_PROCESS:AddScore( State, ScoreText, Score )
self:F2( { State, ScoreText, Score } )
self.Scores[State] = self.Scores[State] or {}
self.Scores[State].ScoreText = ScoreText
self.Scores[State].Score = Score
return self
end
function FSM_PROCESS:onenterAssigned( ProcessUnit )
self:E( "Assign" )
self.Task:Assign()
end
function FSM_PROCESS:onenterFailed( ProcessUnit )
self:E( "Failed" )
self.Task:Fail()
end
function FSM_PROCESS:onenterSuccess( ProcessUnit )
self:E( "Success" )
self.Task:Success()
end
--- StateMachine callback function for a FSM_PROCESS
-- @param #FSM_PROCESS self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function FSM_PROCESS:onstatechange( ProcessUnit, Event, From, To, Dummy )
self:E( { ProcessUnit, Event, From, To, Dummy, self:IsTrace() } )
if self:IsTrace() then
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
end
self:E( self.Scores[To] )
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
if self.Scores[To] then
local Task = self.Task
local Scoring = Task:GetScoring()
if Scoring then
Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score )
end
end
end
--- FSM_TASK class
-- @type FSM_TASK
-- @field Tasking.Task#TASK_BASE Task
-- @extends Core.StateMachine#FSM
FSM_TASK = {
ClassName = "FSM_TASK",
}
--- Creates a new FSM_TASK object.
-- @param #FSM_TASK self
-- @param #table FSMT
-- @param Tasking.Task#TASK_BASE Task
-- @param Wrapper.Unit#UNIT TaskUnit
-- @return #FSM_TASK
function FSM_TASK:New( FSMT )
local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FSMT ) ) -- Core.StateMachine#FSM_TASK
self["onstatechange"] = self.OnStateChange
return self
end
function FSM_TASK:_call_handler( handler, params )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, unpack( params ) )
end
end
do -- FSM_SET
--- FSM_SET class
-- @type FSM_SET
-- @field Core.Set#SET_BASE Set
-- @extends Fsm.Fsm#FSM
FSM_SET = {
ClassName = "FSM_SET",
}
--- Creates a new FSM_SET object.
-- @param #FSM_SET self
-- @param #table FSMT Finite State Machine Table
-- @param Set_SET_BASE FSMSet (optional) The Set object that the FSM_SET governs.
-- @return #FSM_SET
function FSM_SET:New( FSMT, FSMSet )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Fsm.Fsm#FSM_SET
if FSMSet then
self:Set( FSMSet )
end
return self
end
--- Sets the SET_BASE object that the FSM_SET governs.
-- @param #FSM_SET self
-- @param Core.Set#SET_BASE FSMSet
-- @return #FSM_SET
function FSM_SET:Set( FSMSet )
self:F( FSMSet )
self.Set = FSMSet
end
--- Gets the SET_BASE object that the FSM_SET governs.
-- @param #FSM_SET self
-- @return Core.Set#SET_BASE
function FSM_SET:Get()
return self.Controllable
end
function FSM_SET:_call_handler( handler, params )
if self[handler] then
self:E( "Calling " .. handler )
return self[handler]( self, self.Set, unpack( params ) )
end
end
end
--- FSM_TEMPLATE class
-- @type FSM_TEMPLATE
-- @extends Core.Base#BASE
FSM_TEMPLATE = {
ClassName = "FSM_TEMPLATE",
}
--- Creates a new FSM_TEMPLATE object.
-- @param #FSM_TEMPLATE self
-- @return #FSM_TEMPLATE
function FSM_TEMPLATE:New( Name )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() ) -- #FSM_TEMPLATE
self._StartState = "none"
self._Transitions = {}
self._Processes = {}
self._EndStates = {}
self._Scores = {}
self._Name = Name or ""
return self
end
function FSM_TEMPLATE:AddTransition( From, Event, To )
local Transition = {}
Transition.From = From
Transition.Event = Event
Transition.To = To
self._Transitions[Transition] = Transition
end
function FSM_TEMPLATE:GetTransitions()
return self._Transitions or {}
end
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task.
-- @return Process#PROCESS
function FSM_TEMPLATE:AddProcess( From, Event, ProcessTemplate, ReturnEvents )
self:E( { ProcessTemplate = ProcessTemplate } )
local Process = {}
Process.From = From
Process.Event = Event
Process.Process = ProcessTemplate
Process.Parameters = ProcessTemplate:GetParameters()
Process.ReturnEvents = ReturnEvents
self:E( { From = Process.From, Event = Process.Event, Process = Process.Process._Name, Parameters = Process.Parameters, ReturnEvents = Process.ReturnEvents } )
-- Make the reference table weak.
-- setmetatable( self.options.subs, { __mode = "v" } )
self._Processes[Process] = Process
return ProcessTemplate
end
function FSM_TEMPLATE:GetProcesses()
return self._Processes or {}
end
function FSM_TEMPLATE:GetProcess( From, Event )
for ProcessID, Process in pairs( self:GetProcesses() ) do
if Process.From == From and Process.Event == Event then
self:E( Process )
return Process.Process
end
end
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
end
function FSM_TEMPLATE:SetParameters( Parameters )
self._Parameters = Parameters
end
function FSM_TEMPLATE:GetParameters()
return self._Parameters or {}
end
function FSM_TEMPLATE:AddEndState( State )
self._EndStates[State] = State
end
function FSM_TEMPLATE:GetEndStates()
return self._EndStates or {}
end
function FSM_TEMPLATE:SetStartState( State )
self._StartState = State
end
function FSM_TEMPLATE:GetStartState()
return self._StartState or {}
end
--- Adds a score for the FSM_PROCESS to be achieved.
-- @param #FSM_TEMPLATE self
-- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #FSM_TEMPLATE self
function FSM_TEMPLATE:AddScore( State, ScoreText, Score )
self:F2( { State, ScoreText, Score } )
self._Scores[State] = self._Scores[State] or {}
self._Scores[State].ScoreText = ScoreText
self._Scores[State].Score = Score
return self
end
--- Adds a score for the FSM_PROCESS to be achieved.
-- @param #FSM_TEMPLATE self
-- @param #string From is the From State of the main process.
-- @param #string Event is the Event of the main process.
-- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #FSM_TEMPLATE self
function FSM_TEMPLATE:AddScoreProcess( From, Event, State, ScoreText, Score )
self:F2( { Event, State, ScoreText, Score } )
local Process = self:GetProcess( From, Event )
self:E( { Process = Process._Name, Scores = Process._Scores, State = State, ScoreText = ScoreText, Score = Score } )
Process._Scores[State] = Process._Scores[State] or {}
Process._Scores[State].ScoreText = ScoreText
Process._Scores[State].Score = Score
return Process
end
function FSM_TEMPLATE:GetScores()
return self._Scores or {}
end

View File

@@ -2,7 +2,7 @@
--
-- ===
--
-- 1) @{#PATROLZONE} class, extends @{StateMachine#STATEMACHINE}
-- 1) @{#PATROLZONE} class, extends @{Fsm.Fsm#FSM}
-- ================================================================
-- The @{#PATROLZONE} class implements the core functions to patrol a @{Zone} by an AIR @{Controllable} @{Group}.
-- The patrol algorithm works that for each airplane patrolling, upon arrival at the patrol zone,
@@ -68,7 +68,7 @@
--
-- --- State transition function for the PATROLZONE **Patrol** object
-- -- @param #PATROLZONE self
-- -- @param Controllable#CONTROLLABLE AIGroup
-- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup
-- -- @return #boolean If false is returned, then the OnAfter state transition method will not be called.
-- function Patrol:OnBeforeRTB( AIGroup )
-- AIGroup:MessageToRed( "Returning to base", 20 )
@@ -78,8 +78,8 @@
--
-- --- State transition function for the PATROLZONE **Patrol** object
-- -- @param #PATROLZONE self
-- -- @param Controllable#CONTROLLABLE AIGroup
-- -- @return #Controllable#CONTROLLABLE The new AIGroup object that is set to be patrolling the zone.
-- -- @param Wrapper.Controllable#CONTROLLABLE AIGroup
-- -- @return #Wrapper.Controllable#CONTROLLABLE The new AIGroup object that is set to be patrolling the zone.
-- function Patrol:OnAfterRTB( AIGroup )
-- return PatrolSpawn:Spawn()
-- end
@@ -137,25 +137,25 @@
--- OnBefore State Transition Function
-- @function [parent=#PATROLZONE] OnBeforeRoute
-- @param #PATROLZONE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #boolean
--- OnAfter State Transition Function
-- @function [parent=#PATROLZONE] OnAfterRoute
-- @param #PATROLZONE self
-- @param Controllable#CONTROLLABLE Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
--- PATROLZONE class
-- @type PATROLZONE
-- @field Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @field DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @field DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @field DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @extends StateMachine#STATEMACHINE_CONTROLLABLE
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @extends Fsm.Fsm#STATEMACHINE_CONTROLLABLE
PATROLZONE = {
ClassName = "PATROLZONE",
}
@@ -164,11 +164,11 @@ PATROLZONE = {
--- Creates a new PATROLZONE object
-- @param #PATROLZONE self
-- @param Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #PATROLZONE self
-- @usage
-- -- Define a new PATROLZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
@@ -206,8 +206,8 @@ end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #PATROLZONE self
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #PATROLZONE self
function PATROLZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
@@ -220,8 +220,8 @@ end
--- Sets the floor and ceiling altitude of the patrol.
-- @param #PATROLZONE self
-- @param DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @return #PATROLZONE self
function PATROLZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
@@ -232,7 +232,7 @@ end
--- @param Controllable#CONTROLLABLE AIControllable
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewPatrolRoute( AIControllable )
AIControllable:T( "NewPatrolRoute" )

View File

@@ -2,9 +2,9 @@
--- The PROCESS class
-- @type PROCESS
-- @field Task#TASK_BASE ProcessTask
-- @field Group#GROUP ProcessGroup
-- @field Menu#MENU_GROUP MissionMenu
-- @field Tasking.Task#TASK_BASE ProcessTask
-- @field Wrapper.Group#GROUP ProcessGroup
-- @field Core.Menu#MENU_GROUP MissionMenu
-- @field #string ProcessName
-- @extends Core.StateMachine#STATEMACHINE_CONTROLLABLE
PROCESS = {
@@ -16,10 +16,10 @@ PROCESS = {
--- Instantiates a new TASK Base. Should never be used. Interface Class.
-- @param #PROCESS self
-- @param #string ProcessName
-- @param Unit#UNIT ProcessUnit (Optional) If provided, it defines the UNIT for which the process is running.
-- @param Wrapper.Unit#UNIT ProcessUnit (Optional) If provided, it defines the UNIT for which the process is running.
-- @return #PROCESS
function PROCESS:New( FSMT, ProcessName, ProcessUnit )
local self = BASE:Inherit( self, STATEMACHINE_PROCESS:New( FSMT, ProcessUnit ) )
local self = BASE:Inherit( self, FSM_PROCESS:New( FSMT, ProcessUnit ) )
self:F()
if ProcessUnit then
@@ -35,7 +35,7 @@ end
--- Gets the Group of the process.
-- @param #PROCESS self
-- @return Group#GROUP
-- @return Wrapper.Group#GROUP
function PROCESS:GetGroup()
return self.ProcessGroup

View File

@@ -2,8 +2,8 @@
--- PROCESS_JTAC class
-- @type PROCESS_JTAC
-- @field Unit#UNIT ProcessUnit
-- @field Set#SET_UNIT TargetSetUnit
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Process#PROCESS
PROCESS_JTAC = {
ClassName = "PROCESS_JTAC",
@@ -14,10 +14,10 @@ PROCESS_JTAC = {
--- Creates a new DESTROY process.
-- @param #PROCESS_JTAC self
-- @param Task#TASK Task
-- @param Unit#UNIT ProcessUnit
-- @param Set#SET_UNIT TargetSetUnit
-- @param Unit#UNIT FACUnit
-- @param Tasking.Task#TASK Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @param Wrapper.Unit#UNIT FACUnit
-- @return #PROCESS_JTAC self
function PROCESS_JTAC:New( Task, ProcessUnit, TargetSetUnit, FACUnit )
@@ -34,7 +34,7 @@ function PROCESS_JTAC:New( Task, ProcessUnit, TargetSetUnit, FACUnit )
self.DisplayCategory = "HQ" -- Targets is the default display category
self.Fsm = STATEMACHINE_PROCESS:New( self, {
self.Fsm = FSM_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Start', from = 'Assigned', to = 'CreatedMenu' },
@@ -66,7 +66,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -77,7 +77,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -123,7 +123,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -131,7 +131,7 @@ function PROCESS_JTAC:OnJTACMenuAwait( Fsm, Event, From, To )
if self.DisplayCount >= self.DisplayInterval then
local TaskJTAC = self.Task -- Task#TASK_JTAC
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
for TargetUnitName, SpotData in pairs( TaskJTAC.Spots) do
local TargetUnit = UNIT:FindByName( TargetUnitName )
@@ -147,16 +147,16 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT TargetUnit
-- @param Wrapper.Unit#UNIT TargetUnit
function PROCESS_JTAC:OnJTACMenuSpot( Fsm, Event, From, To, TargetUnit )
local TargetUnitName = TargetUnit:GetName()
local TaskJTAC = self.Task -- Task#TASK_JTAC
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
TaskJTAC.Spots[TargetUnitName] = TaskJTAC.Spots[TargetUnitName] or {}
@@ -174,16 +174,16 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_JTAC self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Unit#UNIT TargetUnit
-- @param Wrapper.Unit#UNIT TargetUnit
function PROCESS_JTAC:OnJTACMenuCancel( Fsm, Event, From, To, TargetUnit )
local TargetUnitName = TargetUnit:GetName()
local TaskJTAC = self.Task -- Task#TASK_JTAC
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
TaskJTAC.Spots = TaskJTAC.Spots or {}
if TaskJTAC.Spots[TargetUnitName] then

View File

@@ -2,8 +2,8 @@
--- PROCESS_PICKUP class
-- @type PROCESS_PICKUP
-- @field Unit#UNIT ProcessUnit
-- @field Set#SET_UNIT TargetSetUnit
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Core.Set#SET_UNIT TargetSetUnit
-- @extends Process#PROCESS
PROCESS_PICKUP = {
ClassName = "PROCESS_PICKUP",
@@ -14,9 +14,9 @@ PROCESS_PICKUP = {
--- Creates a new DESTROY process.
-- @param #PROCESS_PICKUP self
-- @param Task#TASK Task
-- @param Unit#UNIT ProcessUnit
-- @param Set#SET_UNIT TargetSetUnit
-- @param Tasking.Task#TASK Task
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Core.Set#SET_UNIT TargetSetUnit
-- @return #PROCESS_PICKUP self
function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit )
@@ -29,7 +29,7 @@ function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit )
self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "HQ" -- Targets is the default display category
self.Fsm = STATEMACHINE_PROCESS:New( self, {
self.Fsm = FSM_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Start', from = 'Assigned', to = 'Navigating' },
@@ -57,7 +57,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -68,7 +68,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -89,11 +89,11 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
-- @param Core.Event#EVENTDATA Event
function PROCESS_PICKUP:OnHitTarget( Fsm, Event, From, To, Event )
@@ -115,7 +115,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -126,11 +126,11 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA DCSEvent
-- @param Core.Event#EVENTDATA DCSEvent
function PROCESS_PICKUP:OnKilled( Fsm, Event, From, To )
self:NextEvent( Fsm.Restart )
@@ -139,7 +139,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -151,7 +151,7 @@ end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_PICKUP self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param Fsm.Fsm#FSM_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -162,7 +162,7 @@ end
--- DCS Events
--- @param #PROCESS_PICKUP self
-- @param Event#EVENTDATA Event
-- @param Core.Event#EVENTDATA Event
function PROCESS_PICKUP:EventDead( Event )
if Event.IniDCSUnit then

View File

@@ -0,0 +1,242 @@
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
--
-- ===
--
-- # @{#PROCESS_ROUTE} FSM class, extends @{Process#PROCESS}
--
-- ## PROCESS_ROUTE state machine:
--
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below.
-- Each derived class follows exactly the same process, using the same events and following the same state transitions,
-- but will have **different implementation behaviour** upon each event or state transition.
--
-- ### PROCESS_ROUTE **Events**:
--
-- These are the events defined in this class:
--
-- * **Start**: The process is started. The process will go into the Report state.
-- * **Report**: The process is reporting to the player the route to be followed.
-- * **Route**: The process is routing the controllable.
-- * **Pause**: The process is pausing the route of the controllable.
-- * **Arrive**: The controllable has arrived at a route point.
-- * **More**: There are more route points that need to be followed. The process will go back into the Report state.
-- * **NoMore**: There are no more route points that need to be followed. The process will go into the Success state.
--
-- ### PROCESS_ROUTE **Event methods**:
--
-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process.
-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine:
--
-- * **Immediate**: The event method has exactly the name of the event.
-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed.
--
-- ### PROCESS_ROUTE **States**:
--
-- * **None**: The controllable did not receive route commands.
-- * **Arrived (*)**: The controllable has arrived at a route point.
-- * **Aborted (*)**: The controllable has aborted the route path.
-- * **Routing**: The controllable is understay to the route point.
-- * **Pausing**: The process is pausing the routing. AI air will go into hover, AI ground will stop moving. Players can fly around.
-- * **Success (*)**: All route points were reached.
-- * **Failed (*)**: The process has failed.
--
-- (*) End states of the process.
--
-- ### PROCESS_ROUTE state transition methods:
--
-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
-- There are 2 moments when state transition methods will be called by the state machine:
--
-- * **Before** the state transition.
-- The state transition method needs to start with the name **OnBefore + the name of the state**.
-- If the state transition method returns false, then the processing of the state transition will not be done!
-- If you want to change the behaviour of the AIControllable at this event, return false,
-- but then you'll need to specify your own logic using the AIControllable!
--
-- * **After** the state transition.
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
-- These state transition methods need to provide a return value, which is specified at the function description.
--
-- ===
--
-- # 1) @{#PROCESS_ROUTE_ZONE} class, extends @{Fsm.Route#PROCESS_ROUTE}
--
-- The PROCESS_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}.
-- The player receives on perioding times messages with the coordinates of the route to follow.
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
--
-- # 1.1) PROCESS_ROUTE_ZONE constructor:
--
-- * @{#PROCESS_ROUTE_ZONE.New}(): Creates a new PROCESS_ROUTE_ZONE object.
--
-- ===
--
-- @module Route
do -- PROCESS_ROUTE
--- PROCESS_ROUTE class
-- @type PROCESS_ROUTE
-- @field Tasking.Task#TASK TASK
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends Core.StateMachine#FSM_TEMPLATE
PROCESS_ROUTE = {
ClassName = "PROCESS_ROUTE",
}
--- Creates a new routing state machine. The process will route a CLIENT to a ZONE until the CLIENT is within that ZONE.
-- @param #PROCESS_ROUTE self
-- @return #PROCESS_ROUTE self
function PROCESS_ROUTE:New()
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_TEMPLATE:New( "PROCESS_ROUTE" ) ) -- Core.StateMachine#FSM_TEMPLATE
self:AddTransition( "None", "Start", "Routing" )
self:AddTransition( "*", "Report", "Reporting" )
self:AddTransition( "*", "Route", "Routing" )
self:AddTransition( "Routing", "Pause", "Pausing" )
self:AddTransition( "*", "Abort", "Aborted" )
self:AddTransition( "Routing", "Arrive", "Arrived" )
self:AddTransition( "Arrived", "Success", "Success" )
self:AddTransition( "*", "Fail", "Failed" )
self:AddTransition( "", "", "" )
self:AddTransition( "", "", "" )
self:AddEndState( "Arrived" )
self:AddEndState( "Failed" )
self:SetStartState( "None" )
return self
end
--- Task Events
--- StateMachine callback function
-- @param #PROCESS_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ROUTE:onafterStart( ProcessUnit, Event, From, To )
self:__Route( 1 )
end
--- Check if the controllable has arrived.
-- @param #PROCESS_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @return #boolean
function PROCESS_ROUTE:onfuncHasArrived( ProcessUnit )
return false
end
--- StateMachine callback function
-- @param #PROCESS_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ROUTE:onbeforeRoute( ProcessUnit, Event, From, To )
if ProcessUnit:IsAlive() then
local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic
if self.DisplayCount >= self.DisplayInterval then
self:T( { HasArrived = HasArrived } )
if not HasArrived then
self:__Report( 1 )
end
self.DisplayCount = 1
else
self.DisplayCount = self.DisplayCount + 1
end
self:T( { DisplayCount = self.DisplayCount } )
if HasArrived then
self:__Arrive( 1 )
else
self:__Route( 1 )
end
return HasArrived -- if false, then the event will not be executed...
end
return false
end
end -- PROCESS_ROUTE
do -- PROCESS_ROUTE_ZONE
--- PROCESS_ROUTE_ZONE class
-- @type PROCESS_ROUTE_ZONE
-- @field Tasking.Task#TASK TASK
-- @field Wrapper.Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends #PROCESS_ROUTE
PROCESS_ROUTE_ZONE = {
ClassName = "PROCESS_ROUTE_ZONE",
}
--- Creates a new routing state machine. The task will route a controllable to a ZONE until the controllable is within that ZONE.
-- @param #PROCESS_ROUTE_ZONE self
-- @param Zone#ZONE_BASE TargetZone
function PROCESS_ROUTE_ZONE:New( TargetZone )
local self = BASE:Inherit( self, PROCESS_ROUTE:New() ) -- #PROCESS_ROUTE_ZONE
self:SetParameters( {
TargetZone = TargetZone,
DisplayInterval = 30,
DisplayCount = 30,
DisplayMessage = true,
DisplayTime = 10, -- 10 seconds is the default
DisplayCategory = "HQ", -- Route is the default display category
} )
return self
end
--- Method override to check if the controllable has arrived.
-- @param #PROCESS_ROUTE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @return #boolean
function PROCESS_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
if ProcessUnit:IsInZone( self.TargetZone ) then
local RouteText = ProcessUnit:GetCallsign() .. ": You have arrived within the zone!"
MESSAGE:New( RouteText, self.DisplayTime, self.DisplayCategory ):ToGroup( ProcessUnit:GetGroup() )
end
return ProcessUnit:IsInZone( self.TargetZone )
end
--- Task Events
--- StateMachine callback function
-- @param #PROCESS_ROUTE_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ROUTE_ZONE:onenterReporting( ProcessUnit, Event, From, To )
local ZoneVec2 = self.TargetZone:GetVec2()
local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y )
local TaskUnitVec2 = ProcessUnit:GetVec2()
local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y )
local RouteText = ProcessUnit:GetCallsign() .. ": Route to " .. TaskUnitPointVec2:GetBRText( ZonePointVec2 ) .. " km to target."
MESSAGE:New( RouteText, self.DisplayTime, self.DisplayCategory ):ToGroup( ProcessUnit:GetGroup() )
end
end -- PROCESS_ROUTE_ZONE

View File

@@ -0,0 +1,199 @@
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
--
-- ===
--
-- # @{#PROCESS_SMOKE} FSM class, extends @{Process#PROCESS}
--
-- ## PROCESS_SMOKE state machine:
--
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
-- All derived classes from this class will start with the class name, followed by a \_. See the relevant derived class descriptions below.
-- Each derived class follows exactly the same process, using the same events and following the same state transitions,
-- but will have **different implementation behaviour** upon each event or state transition.
--
-- ### PROCESS_SMOKE **Events**:
--
-- These are the events defined in this class:
--
-- * **Start**: The process is started.
-- * **Next**: The process is smoking the targets in the given zone.
--
-- ### PROCESS_SMOKE **Event methods**:
--
-- Event methods are available (dynamically allocated by the state machine), that accomodate for state transitions occurring in the process.
-- There are two types of event methods, which you can use to influence the normal mechanisms in the state machine:
--
-- * **Immediate**: The event method has exactly the name of the event.
-- * **Delayed**: The event method starts with a __ + the name of the event. The first parameter of the event method is a number value, expressing the delay in seconds when the event will be executed.
--
-- ### PROCESS_SMOKE **States**:
--
-- * **None**: The controllable did not receive route commands.
-- * **AwaitSmoke (*)**: The process is awaiting to smoke the targets in the zone.
-- * **Smoking (*)**: The process is smoking the targets in the zone.
-- * **Failed (*)**: The process has failed.
--
-- (*) End states of the process.
--
-- ### PROCESS_SMOKE state transition methods:
--
-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
-- There are 2 moments when state transition methods will be called by the state machine:
--
-- * **Before** the state transition.
-- The state transition method needs to start with the name **OnBefore + the name of the state**.
-- If the state transition method returns false, then the processing of the state transition will not be done!
-- If you want to change the behaviour of the AIControllable at this event, return false,
-- but then you'll need to specify your own logic using the AIControllable!
--
-- * **After** the state transition.
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
-- These state transition methods need to provide a return value, which is specified at the function description.
--
-- ===
--
-- # 1) @{#PROCESS_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#PROCESS_SMOKE}
--
-- The PROCESS_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}.
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
-- At random intervals, a new target is smoked.
--
-- # 1.1) PROCESS_SMOKE_TARGETS_ZONE constructor:
--
-- * @{#PROCESS_SMOKE_TARGETS_ZONE.New}(): Creates a new PROCESS_SMOKE_TARGETS_ZONE object.
--
-- ===
--
-- @module Smoke
do -- PROCESS_SMOKE
--- PROCESS_SMOKE class
-- @type PROCESS_SMOKE
-- @extends Core.StateMachine#FSM_TEMPLATE
PROCESS_SMOKE = {
ClassName = "PROCESS_SMOKE",
}
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #PROCESS_SMOKE self
-- @return #PROCESS_SMOKE
function PROCESS_SMOKE:New()
-- Inherits from BASE
local self = BASE:Inherit( self, FSM_TEMPLATE:New( "PROCESS_SMOKE" ) ) -- Core.StateMachine#FSM_TEMPLATE
self:AddTransition( "None", "Start", "AwaitSmoke" )
self:AddTransition( "AwaitSmoke", "Next", "Smoking" )
self:AddTransition( "Smoking", "Next", "AwaitSmoke" )
self:AddTransition( "*", "Stop", "Success" )
self:AddTransition( "*", "Fail", "Failed" )
self:AddEndState( "Failed" )
self:AddEndState( "Success" )
self:SetStartState( "None" )
return self
end
--- Task Events
--- StateMachine callback function
-- @param #PROCESS_SMOKE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_SMOKE:onafterStart( ProcessUnit, Event, From, To )
local ProcessGroup = ProcessUnit:GetGroup()
local MissionMenu = self:GetMission():GetMissionMenu( ProcessGroup )
local function MenuSmoke( MenuParam )
self:E( MenuParam )
local self = MenuParam.self
local SmokeColor = MenuParam.SmokeColor
self.SmokeColor = SmokeColor
self:__Next( 1 )
end
self.Menu = MENU_GROUP:New( ProcessGroup, "Target acquisition", MissionMenu )
self.MenuSmokeBlue = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop blue smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Blue } )
self.MenuSmokeGreen = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop green smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Green } )
self.MenuSmokeOrange = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Orange smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Orange } )
self.MenuSmokeRed = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Red smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Red } )
self.MenuSmokeWhite = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop White smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.White } )
end
end
do -- PROCESS_SMOKE_TARGETS_ZONE
--- PROCESS_SMOKE_TARGETS_ZONE class
-- @type PROCESS_SMOKE_TARGETS_ZONE
-- @field Set#SET_UNIT TargetSetUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends #PROCESS_SMOKE
PROCESS_SMOKE_TARGETS_ZONE = {
ClassName = "PROCESS_SMOKE_TARGETS_ZONE",
}
-- function PROCESS_SMOKE_TARGETS_ZONE:_Destructor()
-- self:E("_Destructor")
--
-- self.Menu:Remove()
-- self:EventRemoveAll()
-- end
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #PROCESS_SMOKE_TARGETS_ZONE self
-- @param Set#SET_UNIT TargetSetUnit
-- @param Zone#ZONE_BASE TargetZone
function PROCESS_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone )
local self = BASE:Inherit( self, PROCESS_SMOKE:New() ) -- #PROCESS_SMOKE
self:SetParameters( { TargetSetUnit, TargetZone } )
return self
end
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #PROCESS_SMOKE_TARGETS_ZONE self
-- @param Set#SET_UNIT TargetSetUnit
-- @param Zone#ZONE_BASE TargetZone
-- @return #PROCESS_SMOKE_TARGETS_ZONE self
function PROCESS_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone )
self.TargetSetUnit = TargetSetUnit
self.TargetZone = TargetZone
return self
end
--- StateMachine callback function
-- @param #PROCESS_SMOKE_TARGETS_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_SMOKE_TARGETS_ZONE:onenterSmoking( ProcessUnit, Event, From, To )
self.TargetSetUnit:ForEachUnit(
--- @param Wrapper.Unit#UNIT SmokeUnit
function( SmokeUnit )
if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then
SCHEDULER:New( self,
function()
if SmokeUnit:IsAlive() then
SmokeUnit:Smoke( self.SmokeColor, 150 )
end
end, {}, math.random( 10, 60 )
)
end
end
)
end
end