mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
435 lines
14 KiB
Lua
435 lines
14 KiB
Lua
--- **Ops** - Operation with multiple phases.
|
|
--
|
|
-- ## Main Features:
|
|
--
|
|
-- * Define operation phases
|
|
-- * Dedicate resources to operations
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Example Missions:
|
|
--
|
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Operation).
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **funkyfranky**
|
|
--
|
|
-- ===
|
|
-- @module Ops.Operation
|
|
-- @image OPS_Operation.png
|
|
|
|
|
|
--- OPERATION class.
|
|
-- @type OPERATION
|
|
-- @field #string ClassName Name of the class.
|
|
-- @field #number verbose Verbosity level.
|
|
-- @field #string lid Class id string for output to DCS log file.
|
|
-- @field #string name Name of the operation.
|
|
-- @field #table cohorts Dedicated cohorts.
|
|
-- @field #table legions Dedicated legions.
|
|
-- @field #table phases Phases.
|
|
-- @field #number counterPhase Running number counting the phases.
|
|
-- @field #OPERATION.Phase phase Currently active phase (if any).
|
|
--
|
|
-- @extends Core.Fsm#FSM
|
|
|
|
--- *A warrior's mission is to foster the success of others.* -- Morihei Ueshiba
|
|
--
|
|
-- ===
|
|
--
|
|
-- # The OPERATION Concept
|
|
--
|
|
--
|
|
--
|
|
-- @field #OPERATION
|
|
OPERATION = {
|
|
ClassName = "OPERATION",
|
|
verbose = 0,
|
|
lid = nil,
|
|
cohorts = {},
|
|
legions = {},
|
|
phases = {},
|
|
counterPhase = 0,
|
|
}
|
|
|
|
--- Global mission counter.
|
|
_OPERATIONID=0
|
|
|
|
--- Operation phase.
|
|
-- @type OPERATION.Phase
|
|
-- @field #number uid Unique ID of the phase.
|
|
-- @field #string name Name of the phase.
|
|
-- @field Core.Condition#CONDITION conditionOver Conditions when the phase is over.
|
|
-- @field #boolean isOver If `true`, phase is over.
|
|
|
|
--- OPERATION class version.
|
|
-- @field #string version
|
|
OPERATION.version="0.0.1"
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- TODO list
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- TODO: A lot
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Constructor
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Create a new generic OPERATION object.
|
|
-- @param #OPERATION self
|
|
-- @param #string Name Name of the operation. Be creative! Default "Operation-01" where the last number is a running number.
|
|
-- @return #OPERATION self
|
|
function OPERATION:New(Name)
|
|
|
|
-- Inherit everything from FSM class.
|
|
local self=BASE:Inherit(self, FSM:New()) -- #OPERATION
|
|
|
|
-- Increase global counter.
|
|
_OPERATIONID=_OPERATIONID+1
|
|
|
|
-- Set Name.
|
|
self.name=Name or string.format("Operation-%02d", _OPERATIONID)
|
|
|
|
-- Set log ID.
|
|
self.lid=string.format("%s | ",self.name)
|
|
|
|
|
|
-- FMS start state is PLANNED.
|
|
self:SetStartState("Planned")
|
|
|
|
-- Add FSM transitions.
|
|
-- From State --> Event --> To State
|
|
self:AddTransition("*", "Start", "Running")
|
|
|
|
self:AddTransition("*", "StatusUpdate", "*")
|
|
|
|
self:AddTransition("Running", "Pause", "Paused")
|
|
self:AddTransition("Paused", "Unpause", "Running")
|
|
|
|
self:AddTransition("*", "ChangePhase", "*")
|
|
self:AddTransition("*", "PhaseChange", "*")
|
|
|
|
self:AddTransition("*", "Over", "Over")
|
|
|
|
self:AddTransition("*", "Stop", "Stopped")
|
|
|
|
|
|
------------------------
|
|
--- Pseudo Functions ---
|
|
------------------------
|
|
|
|
--- Triggers the FSM event "StatusUpdate".
|
|
-- @function [parent=#OPERATION] StatusUpdate
|
|
-- @param #OPERATION self
|
|
|
|
--- Triggers the FSM event "Status" after a delay.
|
|
-- @function [parent=#OPERATION] __StatusUpdate
|
|
-- @param #OPERATION self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
|
|
--- Triggers the FSM event "Stop".
|
|
-- @function [parent=#OPERATION] Stop
|
|
-- @param #OPERATION self
|
|
|
|
--- Triggers the FSM event "Stop" after a delay.
|
|
-- @function [parent=#OPERATION] __Stop
|
|
-- @param #OPERATION self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
|
|
--- Triggers the FSM event "PhaseChange".
|
|
-- @function [parent=#OPERATION] PhaseChange
|
|
-- @param #OPERATION self
|
|
-- @param #OPERATION.Phase Phase The new phase.
|
|
|
|
--- Triggers the FSM event "PhaseChange" after a delay.
|
|
-- @function [parent=#OPERATION] __PhaseChange
|
|
-- @param #OPERATION self
|
|
-- @param #number delay Delay in seconds.
|
|
-- @param #OPERATION.Phase Phase The new phase.
|
|
|
|
--- On after "PhaseChange" event.
|
|
-- @function [parent=#OPERATION] OnAfterPhaseChange
|
|
-- @param #OPERATION self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #OPERATION.Phase Phase The new phase.
|
|
|
|
-- Init status update.
|
|
self:__StatusUpdate(-1)
|
|
|
|
return self
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- User API Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Create a new generic OPERATION object.
|
|
-- @param #OPERATION self
|
|
-- @param #string Name Name of the phase. Default "Phase-01" where the last number is a running number.
|
|
-- @param Core.Condition#CONDITION ConditionOver Condition when the phase is over.
|
|
-- @return #OPERATION.Phase Phase table object.
|
|
function OPERATION:AddPhase(Name, ConditionOver)
|
|
|
|
-- Increase phase counter.
|
|
self.counterPhase=self.counterPhase+1
|
|
|
|
local phase={} --#OPERATION.Phase
|
|
phase.uid=self.counterPhase
|
|
phase.name=Name or string.format("Phase-%02d", self.counterPhase)
|
|
phase.conditionOver=ConditionOver or CONDITION:New(Name)
|
|
phase.isOver=false
|
|
|
|
-- Add phase.
|
|
table.insert(self.phases, phase)
|
|
|
|
return phase
|
|
end
|
|
|
|
--- Get a phase by its name.
|
|
-- @param #OPERATION self
|
|
-- @param #string Name Name of the phase. Default "Phase-01" where the last number is a running number.
|
|
-- @return #OPERATION.Phase Phase table object or nil if phase could not be found.
|
|
function OPERATION:GetPhaseByName(Name)
|
|
|
|
for _,_phase in pairs(self.phases or {}) do
|
|
local phase=_phase --#OPERATION.Phase
|
|
if phase.name==Name then
|
|
return phase
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Assign cohort to operation.
|
|
-- @param #OPERATION self
|
|
-- @param Ops.Cohort#COHORT Cohort The cohort
|
|
-- @return #OPERATION self
|
|
function OPERATION:AssignCohort(Cohort)
|
|
|
|
self.cohorts[Cohort.name]=Cohort
|
|
|
|
end
|
|
|
|
--- Assign legion to operation. All cohorts of this legion will be assigned and are only available
|
|
-- @param #OPERATION self
|
|
-- @param Ops.Legion#LEGION Legion The legion to be assigned.
|
|
-- @return #OPERATION self
|
|
function OPERATION:AssignLegion(Legion)
|
|
|
|
self.legions[Legion.alias]=Legion
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Set start and stop time of the operation.
|
|
-- @param #OPERATION self
|
|
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
|
-- @param #string ClockStop (Optional) Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
|
-- @return #OPERATION self
|
|
function OPERATION:SetTime(ClockStart, ClockStop)
|
|
|
|
-- Current mission time.
|
|
local Tnow=timer.getAbsTime()
|
|
|
|
-- Set start time. Default in 5 sec.
|
|
local Tstart=Tnow+5
|
|
if ClockStart and type(ClockStart)=="number" then
|
|
Tstart=Tnow+ClockStart
|
|
elseif ClockStart and type(ClockStart)=="string" then
|
|
Tstart=UTILS.ClockToSeconds(ClockStart)
|
|
end
|
|
|
|
-- Set stop time. Default nil.
|
|
local Tstop=nil
|
|
if ClockStop and type(ClockStop)=="number" then
|
|
Tstop=Tnow+ClockStop
|
|
elseif ClockStop and type(ClockStop)=="string" then
|
|
Tstop=UTILS.ClockToSeconds(ClockStop)
|
|
end
|
|
|
|
self.Tstart=Tstart
|
|
self.Tstop=Tstop
|
|
|
|
if Tstop then
|
|
self.duration=self.Tstop-self.Tstart
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get currrently active phase.
|
|
-- @param #OPERATION self
|
|
-- @return #OPERATION.Phase Current phase or `nil` if no current phase is active.
|
|
function OPERATION:GetPhaseActive()
|
|
return self.phase
|
|
end
|
|
|
|
--- Get next phase.
|
|
-- @param #OPERATION self
|
|
-- @return #OPERATION.Phase Next phase or `nil` if no next phase exists.
|
|
function OPERATION:GetPhaseNext()
|
|
|
|
for _,_phase in pairs(self.phases or {}) do
|
|
local phase=_phase --#OPERATION.Phase
|
|
|
|
if not phase.isOver then
|
|
-- Return first phase that is not over.
|
|
return phase
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Count phases.
|
|
-- @param #OPERATION self
|
|
-- @return #number Number of phases
|
|
function OPERATION:CountPhases()
|
|
|
|
local N=0
|
|
for phasename, phase in pairs(self.phases) do
|
|
N=N+1
|
|
end
|
|
|
|
return N
|
|
end
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Status Update
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- On after "Start" event.
|
|
-- @param #OPERATION self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPERATION:onafterStart(From, Event, To)
|
|
|
|
-- Get
|
|
local Phase=self:GetPhaseNext()
|
|
|
|
if Phase then
|
|
self:PhaseChange(Phase)
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- On after "StatusUpdate" event.
|
|
-- @param #OPERATION self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPERATION:onafterStatusUpdate(From, Event, To)
|
|
|
|
-- Current abs. mission time.
|
|
local Tnow=timer.getAbsTime()
|
|
|
|
-- Current FSM state.
|
|
local fsmstate=self:GetState()
|
|
|
|
-- Current phase.
|
|
local currphase=self:GetPhaseActive()
|
|
local phasename=currphase and currphase.name or "None"
|
|
local Nphase=self:CountPhases()
|
|
|
|
-- General info.
|
|
local text=string.format("State=%s: Phase=%s, Phases=%d", fsmstate, phasename, Nphase)
|
|
self:I(self.lid..text)
|
|
|
|
-- Info on phases.
|
|
local text="Phases:"
|
|
for i,_phase in pairs(self.phases) do
|
|
local phase=_phase --#OPERATION.Phase
|
|
text=text..string.format("\n[%d] %s", i, phase.name)
|
|
end
|
|
if text=="Phases:" then text=text.." None" end
|
|
|
|
-- Next status update.
|
|
self:__StatusUpdate(-30)
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- FSM Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- On after "ChangePhase" event.
|
|
-- @param #OPERATION self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #OPERATION.Phase Phase The new phase.
|
|
function OPERATION:onafterChangePhase(From, Event, To, Phase)
|
|
|
|
-- Debug message.
|
|
self:T(self.lid..string.format("Changed to phase: %s", Phase.name))
|
|
|
|
-- Set currently active phase.
|
|
self.phase=Phase
|
|
|
|
end
|
|
|
|
--- On after "Over" event.
|
|
-- @param #OPERATION self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #OPERATION.Phase Phase The new phase.
|
|
function OPERATION:onafterOver(From, Event, To)
|
|
|
|
-- Debug message.
|
|
self:T(self.lid..string.format("Operation is over!"))
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Misc Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Check phases.
|
|
-- @param #OPERATION self
|
|
function OPERATION:_CheckPhases()
|
|
|
|
-- Currently active phase.
|
|
local phase=self:GetPhaseActive()
|
|
|
|
-- Check if active phase is over.
|
|
if phase then
|
|
phase.isOver=phase.conditionOver:Evaluate()
|
|
end
|
|
|
|
-- If no current phase or current phase is over, get next phase.
|
|
if phase==nil or (phase and phase.isOver) then
|
|
|
|
-- Get next phase.
|
|
local Phase=self:GetPhaseNext()
|
|
|
|
if Phase then
|
|
|
|
-- Change phase to next one.
|
|
self:PhaseChange(Phase)
|
|
|
|
else
|
|
|
|
-- No further phases defined ==> Operation is over.
|
|
self:Over()
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|