diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 9db404093..9ceb850bb 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -116,9 +116,18 @@ function BASE:New() self.__index = self _ClassID = _ClassID + 1 self.ClassID = _ClassID + + return self end +function BASE:_Destructor() + --self:E("_Destructor") + + self:EventRemoveAll() +end + + --- This is the worker method to inherit from a parent class. -- @param #BASE self -- @param Child is the Child class that inherits. @@ -131,6 +140,22 @@ function BASE:Inherit( Child, Parent ) if Child ~= nil then setmetatable( Child, Parent ) Child.__index = Child + + local proxy = newproxy(true) + local proxyMeta = getmetatable(proxy) + + proxyMeta.__gc = function () + -- env.info("In __gc for " .. Child:GetClassNameAndID() ) + if Child._Destructor then + Child:_Destructor() + end + end + + -- keep the userdata from newproxy reachable until the object + -- table is about to be garbage-collected - then the __gc hook + -- will be invoked and the destructor called + rawset(Child, '__proxy', proxy) + end --self:T( 'Inherited from ' .. Parent.ClassName ) return Child diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index e752a7d3e..3c78e6bb9 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -85,9 +85,16 @@ end -- @return #EVENT.Events function EVENT:Init( EventID, EventClass ) self:F3( { _EVENTCODES[EventID], EventClass } ) - if not self.Events[EventID] then + + if not self.Events[EventID] then self.Events[EventID] = {} + + -- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned. + local Meta = {} + setmetatable( self.Events[EventID], Meta ) + Meta.__mode = "k" end + if not self.Events[EventID][EventClass] then self.Events[EventID][EventClass] = {} end diff --git a/Moose Development/Moose/Core/StateMachine.lua b/Moose Development/Moose/Core/StateMachine.lua index fd353d464..1344d8c03 100644 --- a/Moose Development/Moose/Core/StateMachine.lua +++ b/Moose Development/Moose/Core/StateMachine.lua @@ -18,7 +18,7 @@ --- STATEMACHINE class -- @type STATEMACHINE --- @extends Base#BASE +-- @extends Core.Base#BASE STATEMACHINE = { ClassName = "STATEMACHINE", } @@ -34,43 +34,85 @@ function STATEMACHINE:New( options ) --local self = routines.utils.deepCopy( self ) -- Create a new self instance - assert(options.events) + --assert(options.events) --local MT = {} --setmetatable( self, MT ) --self.__index = self self.options = options + self.options.subs = self.options.subs or {} self.current = options.initial or 'none' self.events = {} self.subs = {} self.endstates = {} - for _, event in ipairs(options.events or {}) do - 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 ) - self.events[name] = self.events[name] or { map = {} } - self:_add_to_map(self.events[name].map, event) + for _, event in pairs(options.events or {}) do + self:E({ "events", event }) + self:_eventmap( self.events, event ) end for name, callback in pairs(options.callbacks or {}) do + self:E("callbacks") self[name] = callback end for name, sub in pairs( options.subs or {} ) do + self:E("sub") self:_submap( self.subs, sub, name ) end for name, endstate in pairs( options.endstates or {} ) do + self:E("endstate") self.endstates[endstate] = endstate end return self end +function STATEMACHINE:SetInitialState( State ) + self.current = State +end + +function STATEMACHINE:AddAction( 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 STATEMACHINE:AddProcess( From, Event, Process, ReturnEvents ) + + local sub = {} + sub.FromParent = From + sub.EventParent = Event + sub.fsm = Process + sub.event = "Start" + sub.ReturnEvents = ReturnEvents + + self.options.subs[Event] = sub + + self:_submap( self.subs, sub, nil ) + + self:AddAction( From, Event, "*" ) + + return Process +end + +function STATEMACHINE:GetSubs() + + return self.options.subs +end + + function STATEMACHINE:LoadCallBacks( CallBackTable ) for name, callback in pairs( CallBackTable or {} ) do @@ -79,41 +121,54 @@ function STATEMACHINE:LoadCallBacks( CallBackTable ) end +function STATEMACHINE:_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 STATEMACHINE:_submap( subs, sub, name ) self:E( { sub = sub, name = name } ) - subs[sub.onstateparent] = subs[sub.onstateparent] or {} - subs[sub.onstateparent][sub.oneventparent] = subs[sub.onstateparent][sub.oneventparent] or {} - local Index = #subs[sub.onstateparent][sub.oneventparent] + 1 - subs[sub.onstateparent][sub.oneventparent][Index] = {} - subs[sub.onstateparent][sub.oneventparent][Index].fsm = sub.fsm - subs[sub.onstateparent][sub.oneventparent][Index].event = sub.event - subs[sub.onstateparent][sub.oneventparent][Index].returnevents = sub.returnevents -- these events need to be given to find the correct continue event ... if none given, the processing will stop. - subs[sub.onstateparent][sub.oneventparent][Index].name = name - subs[sub.onstateparent][sub.oneventparent][Index].fsmparent = self + subs[sub.FromParent] = subs[sub.FromParent] or {} + subs[sub.FromParent][sub.EventParent] = subs[sub.FromParent][sub.EventParent] or {} + local Index = #subs[sub.FromParent][sub.EventParent] + 1 + subs[sub.FromParent][sub.EventParent][Index] = {} + subs[sub.FromParent][sub.EventParent][Index].fsm = sub.fsm + subs[sub.FromParent][sub.EventParent][Index].event = sub.event + subs[sub.FromParent][sub.EventParent][Index].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][Index].name = name + subs[sub.FromParent][sub.EventParent][Index].fsmparent = self end function STATEMACHINE:_call_handler(handler, params) - if handler then - return handler( self, unpack(params) ) + if self[handler] then + self:E( "Calling " .. handler ) + return self[handler]( self, unpack(params) ) end end function STATEMACHINE._handler( self, EventName, ... ) - self:F( { EventName, ... } ) + self:E( { EventName, ... } ) - local can, to = self:can(EventName) - self:T( { EventName, can, to } ) + local can, to = self:can( EventName ) + self:E( { EventName, can, to } ) local ReturnValues = nil if can then local from = self.current - local params = { ..., EventName, from, to } + local params = { EventName, from, to, ... } - if self:_call_handler(self["onbefore" .. EventName], params) == false - or self:_call_handler(self["onleave" .. from], params) == false then + if self:_call_handler("onbefore" .. EventName, params) == false + or self:_call_handler("onleave" .. from, params) == false then return false end @@ -121,11 +176,15 @@ function STATEMACHINE._handler( self, EventName, ... ) local execute = true - local subtable = self:_gosub( to, EventName ) + 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:F2( "calling sub: " .. sub.event ) sub.fsm.fsmparent = self - sub.fsm.returnevents = sub.returnevents + sub.fsm.ReturnEvents = sub.ReturnEvents sub.fsm[sub.event]( sub.fsm ) execute = true end @@ -133,28 +192,28 @@ function STATEMACHINE._handler( self, EventName, ... ) local fsmparent, event = self:_isendstate( to ) if fsmparent and event then self:F2( { "end state: ", fsmparent, event } ) - self:_call_handler(self["onenter" .. to] or self["on" .. to], params) - self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params) - self:_call_handler(self["onstatechange"], params) + 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 self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) - self:_call_handler(self["onenter" .. to] or self["on" .. to], params) + self:_call_handler("onenter" .. to, params) self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) - if ( self:_call_handler(self["OnBefore" .. to], params ) ~= false ) then + if ( self:_call_handler("OnBefore" .. to, params ) ~= false ) then self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) - self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params) + self:_call_handler("onafter" .. EventName, params) self:T3( { On = "OnAfter" .. to, callback = self["OnAfter" .. to] } ) - ReturnValues = self:_call_handler(self["OnAfter" .. to], params ) + ReturnValues = self:_call_handler("OnAfter" .. to, params ) end - self:_call_handler(self["onstatechange"], params) + self:_call_handler("onstatechange", params) end return ReturnValues @@ -176,32 +235,30 @@ function STATEMACHINE:_create_transition( EventName ) return function( self, ... ) return self._handler( self, EventName , ... ) end end -function STATEMACHINE:_gosub( parentstate, parentevent ) +function STATEMACHINE:_gosub( ParentFrom, ParentEvent ) local fsmtable = {} - if self.subs[parentstate] and self.subs[parentstate][parentevent] then - return self.subs[parentstate][parentevent] + if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then + self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom] } ) + return self.subs[ParentFrom][ParentEvent] else return {} end end -function STATEMACHINE:_isendstate( state ) - local fsmparent = self.fsmparent - if fsmparent and self.endstates[state] then - self:E( { state = state, endstates = self.endstates, endstate = self.endstates[state] } ) - local returnevent = nil - local fromstate = fsmparent.current - self:E( fromstate ) - self:E( self.returnevents ) - for _, eventname in pairs( self.returnevents ) do - local event = fsmparent.events[eventname] - self:E( event ) - local to = event and event.map[fromstate] or event.map['*'] - if to and to == state then - return fsmparent, eventname - else - self:E( { "could not find parent event name for state", fromstate, to } ) - end +function STATEMACHINE:_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 @@ -209,6 +266,7 @@ function STATEMACHINE:_isendstate( state ) end function STATEMACHINE:_add_to_map(map, event) + self:E( { map, event } ) if type(event.from) == 'string' then map[event.from] = event.to else @@ -216,6 +274,7 @@ function STATEMACHINE:_add_to_map(map, event) map[from] = event.to end end + self:E( { map, event } ) end function STATEMACHINE:is(state) @@ -224,6 +283,7 @@ end function STATEMACHINE:can(e) local event = self.events[e] + self:E( { self.current, event } ) local to = event and event.map[self.current] or event.map['*'] return to ~= nil, to end @@ -252,45 +312,11 @@ function STATEMACHINE:todot(filename) end ---- STATEMACHINE_TASK class --- @type STATEMACHINE_TASK --- @field Task#TASK_BASE Task --- @extends StateMachine#STATEMACHINE -STATEMACHINE_TASK = { - ClassName = "STATEMACHINE_TASK", -} - ---- Creates a new STATEMACHINE_TASK object. --- @param #STATEMACHINE_TASK self --- @param #table FSMT --- @param Task#TASK_BASE Task --- @param Unit#UNIT TaskUnit --- @return #STATEMACHINE_TASK -function STATEMACHINE_TASK:New( FSMT, Task, TaskUnit ) - - local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_PROCESS - - self["onstatechange"] = Task.OnStateChange - self["onAssigned"] = Task.OnAssigned - self["onSuccess"] = Task.OnSuccess - self["onFailed"] = Task.OnFailed - - self.Task = Task - self.TaskUnit = TaskUnit - - return self -end - -function STATEMACHINE_TASK:_call_handler( handler, params ) - if handler then - return handler( self.Task, self.TaskUnit, unpack( params ) ) - end -end --- STATEMACHINE_CONTROLLABLE class -- @type STATEMACHINE_CONTROLLABLE -- @field Controllable#CONTROLLABLE Controllable --- @extends StateMachine#STATEMACHINE +-- @extends Core.StateMachine#STATEMACHINE STATEMACHINE_CONTROLLABLE = { ClassName = "STATEMACHINE_CONTROLLABLE", } @@ -329,14 +355,16 @@ function STATEMACHINE_CONTROLLABLE:GetControllable() end function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params ) - if handler then - return handler( self, self.Controllable, unpack( params ) ) + if self[handler] then + self:E( "Calling " .. handler ) + return self[handler]( self, self.Controllable, unpack( params ) ) end end --- STATEMACHINE_PROCESS class -- @type STATEMACHINE_PROCESS -- @field Process#PROCESS Process +-- @field Tasking.Task#TASK_BASE Task -- @extends Core.StateMachine#STATEMACHINE_CONTROLLABLE STATEMACHINE_PROCESS = { ClassName = "STATEMACHINE_PROCESS", @@ -352,6 +380,92 @@ function STATEMACHINE_PROCESS:New( FSMT ) return self end +--- Sets the task of the process. +-- @param #PROCESS self +-- @param Tasking.Task#TASK_BASE Task +-- @return #PROCESS +function STATEMACHINE_PROCESS:SetTask( Task ) + + self.Task = Task + + return self +end + +--- Gets the task of the process. +-- @param #PROCESS self +-- @return Task#TASK_BASE +function STATEMACHINE_PROCESS:GetTask() + + return self.Task +end + +--- Gets the mission of the process. +-- @param #PROCESS self +-- @return Mission#MISSION +function STATEMACHINE_PROCESS:GetMission() + + return self.Task.Mission +end + + +--- Assign the process to a @{Unit} and activate the process. +-- @param #PROCESS self +-- @param Task.Tasking#TASK_BASE Task +-- @param Wrapper.Unit#UNIT ProcessUnit +-- @return #PROCESS self +function STATEMACHINE_PROCESS:Assign( Task, ProcessUnit ) + self:E( { Task, ProcessUnit } ) + + self:SetControllable( ProcessUnit ) + self:SetTask( Task ) + + self.ProcessGroup = ProcessUnit:GetGroup() + + --self:Activate() + + return self +end + +function STATEMACHINE_PROCESS:onenterAssigned( ProcessUnit ) + + self.Task:Assign() +end + +function STATEMACHINE_PROCESS:onenterSuccess( ProcessUnit ) + + self.Task:Success() +end + +--- STATEMACHINE_TASK class +-- @type STATEMACHINE_TASK +-- @field Task#TASK_BASE Task +-- @extends Core.StateMachine#STATEMACHINE +STATEMACHINE_TASK = { + ClassName = "STATEMACHINE_TASK", +} + +--- Creates a new STATEMACHINE_TASK object. +-- @param #STATEMACHINE_TASK self +-- @param #table FSMT +-- @param Task#TASK_BASE Task +-- @param Unit#UNIT TaskUnit +-- @return #STATEMACHINE_TASK +function STATEMACHINE_TASK:New( FSMT ) + + local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FSMT ) ) -- Core.StateMachine#STATEMACHINE_TASK + + self["onstatechange"] = self.OnStateChange + + return self +end + +function STATEMACHINE_TASK:_call_handler( handler, params ) + if self[handler] then + self:E( "Calling " .. handler ) + return self[handler]( self, unpack( params ) ) + end +end + do -- STATEMACHINE_SET --- STATEMACHINE_SET class @@ -396,8 +510,9 @@ function STATEMACHINE_SET:Get() end function STATEMACHINE_SET:_call_handler( handler, params ) - if handler then - return handler( self, self.Set, unpack( params ) ) + if self[handler] then + self:E( "Calling " .. handler ) + return self[handler]( self, self.Set, unpack( params ) ) end end diff --git a/Moose Development/Moose/Fsm/Process.lua b/Moose Development/Moose/Fsm/Process.lua index bb6c869be..4b180ea1b 100644 --- a/Moose Development/Moose/Fsm/Process.lua +++ b/Moose Development/Moose/Fsm/Process.lua @@ -6,7 +6,7 @@ -- @field Group#GROUP ProcessGroup -- @field Menu#MENU_GROUP MissionMenu -- @field #string ProcessName --- @extends StateMachine#STATEMACHINE_CONTROLLABLE +-- @extends Core.StateMachine#STATEMACHINE_CONTROLLABLE PROCESS = { ClassName = "PROCESS", NextEvent = nil, @@ -19,7 +19,7 @@ PROCESS = { -- @param 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_CONTROLLABLE:New( FSMT, ProcessUnit ) ) + local self = BASE:Inherit( self, STATEMACHINE_PROCESS:New( FSMT, ProcessUnit ) ) self:F() if ProcessUnit then @@ -29,6 +29,7 @@ function PROCESS:New( FSMT, ProcessName, ProcessUnit ) --self.MissionMenu = Task.Mission:GetMissionMenu( self.ProcessGroup ) self.ProcessName = ProcessName + return self end @@ -40,74 +41,20 @@ function PROCESS:GetGroup() return self.ProcessGroup end ---- Sets the task of the process. --- @param #PROCESS self --- @param Tasking.Task#TASK_BASE ProcessTask --- @return #PROCESS -function PROCESS:SetTask( ProcessTask ) - self.ProcessTask = ProcessTask - - return self -end - ---- Gets the task of the process. --- @param #PROCESS self --- @return Task#TASK_BASE -function PROCESS:GetTask() - - return self.ProcessTask -end - ---- Gets the mission of the process. --- @param #PROCESS self --- @return Mission#MISSION -function PROCESS:GetMission() - - return self.ProcessTask.Mission -end - -function PROCESS:ProcessStart() - -end - -function PROCESS:ProcessStop() - self:E("ProcessStop Base Class") - - self:EventRemoveAll() -end - ---- Assign the process to a @{Unit} and activate the process. --- @param #PROCESS self --- @param Unit#UNIT ProcessUnit --- @return #PROCESS self -function PROCESS:Assign( ProcessTask, ProcessUnit ) - - self:SetControllable( ProcessUnit ) - self:SetTask( ProcessTask ) - - self:ProcessStart() - - self.ProcessGroup = ProcessUnit:GetGroup() - --self:Activate() - - return self -end --- Adds a score for the PROCESS to be achieved. -- @param #PROCESS self --- @param Task#TASK_BASE Task The task for which the process needs to account score. -- @param #string ProcessStatus 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 #PROCESS self -function PROCESS:AddScore( Task, ProcessStatus, ScoreText, Score ) +function PROCESS:AddScore( ProcessStatus, ScoreText, Score ) self:F2( { ProcessStatus, ScoreText, Score } ) self.Scores[ProcessStatus] = self.Scores[ProcessStatus] or {} self.Scores[ProcessStatus].ScoreText = ScoreText self.Scores[ProcessStatus].Score = Score - self.Scores[ProcessStatus].Task = Task return self end @@ -118,17 +65,18 @@ end -- @param #string Event -- @param #string From -- @param #string To -function PROCESS:OnStateChange( ProcessUnit, Event, From, To ) - self:E( { self.ProcessName, Event, From, To, ProcessUnit.UnitName } ) +function PROCESS:onstatechange( ProcessUnit, Event, From, To, Dummy ) + self:E( { ProcessUnit, Event, From, To, Dummy } ) 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.Scores[To].Task + local Task = self.Task local Scoring = Task:GetScoring() if Scoring then Scoring:_AddMissionTaskScore( Task.Mission, ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score ) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 7144a07b6..dbfddb868 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -275,18 +275,20 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score ) local MissionName = Mission:GetName() self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } ) + + local PlayerData = self.Players[PlayerName] - if not self.Players[PlayerName].Mission[MissionName] then - self.Players[PlayerName].Mission[MissionName] = {} - self.Players[PlayerName].Mission[MissionName].ScoreTask = 0 - self.Players[PlayerName].Mission[MissionName].ScoreMission = 0 + if not PlayerData.Mission[MissionName] then + PlayerData.Mission[MissionName] = {} + PlayerData.Mission[MissionName].ScoreTask = 0 + PlayerData.Mission[MissionName].ScoreMission = 0 end self:T( PlayerName ) - self:T( self.Players[PlayerName].Mission[MissionName] ) + self:T( PlayerData.Mission[MissionName] ) - self.Players[PlayerName].Score = self.Players[PlayerName].Score + Score - self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score + PlayerData.Score = self.Players[PlayerName].Score + Score + PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " .. Score .. " task score!", @@ -306,10 +308,12 @@ function SCORING:_AddMissionScore( Mission, Text, Score ) local MissionName = Mission:GetName() - self:F( { Mission, Text, Score } ) + self:E( { Mission, Text, Score } ) + self:E( self.Players ) for PlayerName, PlayerData in pairs( self.Players ) do + self:E( PlayerData ) if PlayerData.Mission[MissionName] then PlayerData.Score = PlayerData.Score + Score diff --git a/Moose Development/Moose/Process/Account.lua b/Moose Development/Moose/Process/Account.lua index 58b4dc5e1..cd2b94eb3 100644 --- a/Moose Development/Moose/Process/Account.lua +++ b/Moose Development/Moose/Process/Account.lua @@ -96,10 +96,10 @@ do -- PROCESS_ACCOUNT { name = 'Report', from = '*', to = 'Report' }, { name = 'Event', from = '*', to = 'Account' }, { name = 'More', from = 'Account', to = 'Wait' }, - { name = 'NoMore', from = 'Account', to = 'Success' }, + { name = 'NoMore', from = 'Account', to = 'Accounted' }, { name = 'Fail', from = '*', to = 'Failed' }, }, - endstates = { 'Success', 'Failed' } + endstates = { 'Accounted', 'Failed' } } -- Inherits from BASE @@ -124,8 +124,11 @@ do -- PROCESS_ACCOUNT -- @param #string To function PROCESS_ACCOUNT:onafterStart( ProcessUnit, Event, From, To ) + self:EventOnDead( self.EventDead ) + self:__Wait( 1 ) end + --- StateMachine callback function -- @param #PROCESS_ACCOUNT self @@ -169,6 +172,15 @@ do -- 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:Template( TargetSetUnit, TaskName ) + return { self, arg } + end + --- Creates a new DESTROY process. -- @param #PROCESS_ACCOUNT_DEADS self @@ -182,12 +194,15 @@ do -- PROCESS_ACCOUNT_DEADS self.TargetSetUnit = TargetSetUnit self.TaskName = TaskName - + return self end + + function PROCESS_ACCOUNT_DEADS:_Destructor() + self:E("_Destructor") + + self:RemoveEventsAll() - function PROCESS_ACCOUNT_DEADS:ProcessStart() - self:EventOnDead( self.EventDead ) end --- Process Events @@ -199,6 +214,7 @@ do -- PROCESS_ACCOUNT_DEADS -- @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 ) @@ -211,7 +227,7 @@ do -- PROCESS_ACCOUNT_DEADS -- @param #string Event -- @param #string From -- @param #string To - function PROCESS_ACCOUNT_DEADS:onenterAccount( ProcessUnit, EventData, Event, From, To ) + function PROCESS_ACCOUNT_DEADS:onenterAccount( ProcessUnit, Event, From, To, EventData ) self:T( { ProcessUnit, EventData, Event, From, To } ) self:T({self.Controllable}) diff --git a/Moose Development/Moose/Process/Assign.lua b/Moose Development/Moose/Process/Assign.lua index 4cc51bd00..11d80cb57 100644 --- a/Moose Development/Moose/Process/Assign.lua +++ b/Moose Development/Moose/Process/Assign.lua @@ -134,6 +134,14 @@ do -- 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:Template( TaskBriefing ) + return { self, { TaskBriefing } } + end + + --- 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 diff --git a/Moose Development/Moose/Process/Route.lua b/Moose Development/Moose/Process/Route.lua index 482f070a4..ba3451623 100644 --- a/Moose Development/Moose/Process/Route.lua +++ b/Moose Development/Moose/Process/Route.lua @@ -107,7 +107,7 @@ do -- PROCESS_ROUTE { name = 'Fail', from = '*', to = 'Failed' }, }, endstates = { - 'Arrived', 'Failed', 'Success' + 'Arrived', 'Failed' }, } @@ -150,10 +150,10 @@ do -- PROCESS_ROUTE -- @param #string Event -- @param #string From -- @param #string To - function PROCESS_ROUTE:onafterRoute( ProcessUnit, Event, From, To ) + function PROCESS_ROUTE:onbeforeRoute( ProcessUnit, Event, From, To ) if ProcessUnit:IsAlive() then - local HasArrived = self:HasArrived( ProcessUnit ) + local HasArrived = self:HasArrived( ProcessUnit ) -- Polymorphic if self.DisplayCount >= self.DisplayInterval then self:T( { HasArrived = HasArrived } ) if not HasArrived then @@ -165,7 +165,12 @@ do -- PROCESS_ROUTE end self:T( { DisplayCount = self.DisplayCount } ) - self:__Route( 1 ) + + if HasArrived then + self:__Arrive( 1 ) + else + self:__Route( 1 ) + end return HasArrived -- if false, then the event will not be executed... end @@ -189,6 +194,14 @@ do -- PROCESS_ROUTE_ZONE 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:Template( TargetZone ) + return { self, arg } + end --- Creates a new routing state machine. The task will route a controllable to a ZONE until the controllable is within that ZONE. @@ -206,9 +219,15 @@ do -- PROCESS_ROUTE_ZONE --- Method override to check if the controllable has arrived. -- @param #PROCESS_ROUTE self - -- @param Controllable#CONTROLLABLE ProcessUnit + -- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit -- @return #boolean function PROCESS_ROUTE_ZONE:HasArrived( 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 diff --git a/Moose Development/Moose/Process/Smoke.lua b/Moose Development/Moose/Process/Smoke.lua index 0df9b4c93..69e926efb 100644 --- a/Moose Development/Moose/Process/Smoke.lua +++ b/Moose Development/Moose/Process/Smoke.lua @@ -144,13 +144,20 @@ do -- PROCESS_SMOKE_TARGETS_ZONE ClassName = "PROCESS_SMOKE_TARGETS_ZONE", } - function PROCESS_SMOKE_TARGETS_ZONE:ProcessStop() - self:E("ProcessStop Detailed") + 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:Template( TargetSetUnit, TargetZone ) + return { self, arg } + 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 diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 62bc19ca8..006f74aea 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -9,8 +9,8 @@ -- * @{#TASK_BASE.AssignToGroup}():Assign a task to a group (of players). -- * @{#TASK_BASE.AddProcess}():Add a @{Process} to a task. -- * @{#TASK_BASE.RemoveProcesses}():Remove a running @{Process} from a running task. --- * @{#TASK_BASE.AddStateMachine}():Add a @{StateMachine} to a task. --- * @{#TASK_BASE.RemoveStateMachines}():Remove @{StateMachine}s from a task. +-- * @{#TASK_BASE.SetStateMachine}():Set a @{StateMachine} to a task. +-- * @{#TASK_BASE.RemoveStateMachine}():Remove @{StateMachine} from a task. -- * @{#TASK_BASE.HasStateMachine}():Enquire if the task has a @{StateMachine} -- * @{#TASK_BASE.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK_BASE}. -- * @{#TASK_BASE.UnAssignFromUnit}(): Unassign the task from a unit. @@ -69,22 +69,29 @@ TASK_BASE = { --- Instantiates a new TASK_BASE. Should never be used. Interface Class. -- @param #TASK_BASE self --- @param Mission#MISSION The mission wherein the Task is registered. --- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. +-- @param Mission#MISSION Mission The mission wherein the Task is registered. +-- @param Set#SET_GROUP SetGroupAssign The set of groups for which the Task can be assigned. -- @param #string TaskName The name of the Task -- @param #string TaskType The type of the Task -- @param #string TaskCategory The category of the Task (A2G, A2A, Transport, ... ) -- @return #TASK_BASE self -function TASK_BASE:New( Mission, SetGroup, TaskName, TaskType, TaskCategory ) +function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType, TaskCategory ) + + + local self = BASE:Inherit( self, STATEMACHINE_TASK:New( {} ) ) + + self:SetInitialState( "Planned" ) + self:AddAction( "Planned", "Assign", "Assigned" ) + self:AddAction( "Assigned", "Success", "Success" ) + self:AddAction( "*", "Fail", "Failed" ) - local self = BASE:Inherit( self, BASE:New() ) self:E( "New TASK " .. TaskName ) self.Processes = {} self.Fsm = {} self.Mission = Mission - self.SetGroup = SetGroup + self.SetGroup = SetGroupAssign self:SetCategory( TaskCategory ) self:SetType( TaskType ) @@ -92,6 +99,9 @@ function TASK_BASE:New( Mission, SetGroup, TaskName, TaskType, TaskCategory ) self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences .. self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "." + + self.FsmTemplate = self.FsmTemplate or STATEMACHINE_PROCESS:New( {} ) + self.FsmTemplate:SetTask( self ) return self end @@ -109,6 +119,10 @@ function TASK_BASE:CleanUp() return nil end +function TASK_BASE:GetFsmTemplate() + + return self.FsmTemplate +end --- Assign the @{Task}to a @{Group}. -- @param #TASK_BASE self @@ -128,6 +142,7 @@ function TASK_BASE:AssignToGroup( TaskGroup ) for UnitID, UnitData in pairs( TaskUnits ) do local TaskUnit = UnitData -- Unit#UNIT local PlayerName = TaskUnit:GetPlayerName() + self:E(PlayerName) if PlayerName ~= nil or PlayerName ~= "" then self:AssignToUnit( TaskUnit ) end @@ -136,6 +151,66 @@ function TASK_BASE:AssignToGroup( TaskGroup ) return self end +--- Assign the @{Task} to an alive @{Unit}. +-- @param #TASK_BASE self +-- @param Unit#UNIT TaskUnit +-- @return #TASK_BASE self +function TASK_BASE:AssignToUnit( TaskUnit ) + self:F( TaskUnit:GetName() ) + + -- Copy the FsmTemplate, which is not assigned to a Unit. + -- Assign the FsmTemplate to the TaskUnit. + local FsmTemplate = self:GetFsmTemplate() + local FsmUnit = UTILS.DeepCopy( FsmTemplate ) + FsmUnit:Assign( self, TaskUnit ) + + -- Assign each FsmSub in FsmUnit to the TaskUnit. + -- (This is not done during the copy). + self:E(FsmUnit:GetSubs()) + for FsmSubID, FsmSub in pairs( FsmUnit:GetSubs() ) do + self:E( { "Sub ID", FsmSub.fsm:GetClassNameAndID(), FsmSubID } ) + FsmSub.fsm:Assign( self, TaskUnit ) + end + + +-- for TransitionID, TransitionTemplate in ipairs( self.TransitionTemplates ) do +-- self:E( TransitionTemplate ) +-- FSM:AddTransition( TransitionTemplate.From, TransitionTemplate.Event, TransitionTemplate.To ) +-- end + + -- Copy each ProcessTemplate for the TaskUnit that is alive, as set as a template at the Parent. + -- Each Process will start From a state, upon a fired Event. + -- Upon finalization of the Process, the ReturnEvents contain for which Return state which Event of the Parent needs to be fired. + -- The Return state of the Process is transferred to the Parent. +-- for ProcessID, ProcessTemplate in ipairs( self.ProcessTemplates ) do +-- FSM:AddProcess( ProcessTemplate.From, ProcessTemplate.Event, Process, ProcessTemplate.ReturnEvents ) +-- self:E( { "Process ID", Process:GetClassNameAndID() } ) +-- Process:Assign( self, TaskUnit ) +-- end + + FsmUnit:SetInitialState( "Planned" ) + FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow. + + return self +end + +--- UnAssign the @{Task} from an alive @{Unit}. +-- @param #TASK_BASE self +-- @param Unit#UNIT TaskUnit +-- @return #TASK_BASE self +function TASK_BASE:UnAssignFromUnit( TaskUnitName ) + self:F( TaskUnitName ) + + if self:HasStateMachine( TaskUnitName ) == true then + self:E("RemoveStateMachines") + self:RemoveStateMachine( TaskUnitName ) + end + + return self +end + + + --- Send the briefng message of the @{Task} to the assigned @{Group}s. -- @param #TASK_BASE self function TASK_BASE:SendBriefingToAssignedGroups() @@ -186,33 +261,6 @@ function TASK_BASE:IsAssignedToGroup( TaskGroup ) return false end ---- Assign the @{Task} to an alive @{Unit}. --- @param #TASK_BASE self --- @param Unit#UNIT TaskUnit --- @return #TASK_BASE self -function TASK_BASE:AssignToUnit( TaskUnit ) - self:F( TaskUnit:GetName() ) - - return nil -end - ---- UnAssign the @{Task} from an alive @{Unit}. --- @param #TASK_BASE self --- @param Unit#UNIT TaskUnit --- @return #TASK_BASE self -function TASK_BASE:UnAssignFromUnit( TaskUnitName ) - self:F( TaskUnitName ) - - if self:HasStateMachine( TaskUnitName ) == true then - self:E("RemoveStateMachines") - self:RemoveStateMachines( TaskUnitName ) - self:E("RemoveProcesses") - self:RemoveProcesses( TaskUnitName ) - end - - return self -end - --- Set the menu options of the @{Task} to all the groups in the SetGroup. -- @param #TASK_BASE self -- @return #TASK_BASE self @@ -406,31 +454,6 @@ function TASK_BASE:GetTaskName() end ---- This is the key worker function for the class. Instantiate a new Process based on the ProcessName to @{Task} and assign it to the ProcessUnit. --- @param #TASK_BASE self --- @param Unit#UNIT ProcessUnit The unit to which the process should be assigned. --- @param #string ProcessName The name of the Process. --- @return Process#PROCESS The Process that was added. -function TASK_BASE:AssignProcess( ProcessUnit, ProcessName ) - self:F( { ProcessName } ) - local ProcessUnitName = ProcessUnit:GetName() - - -- Create the Process instance base on the ProcessClasses collection assigned to the Task - local ProcessTemplate, ProcessArguments - ProcessTemplate = self:GetProcessTemplate( ProcessName ) - - self:E( "Deepcopy" ) - -- This statement copies the process template assigned to the task and creates a new process. - local Process = UTILS.DeepCopy( ProcessTemplate ) -- Fsm.Process#PROCESS - Process:Assign( self, ProcessUnit ) - - self.Processes = self.Processes or {} - self.Processes[ProcessUnitName] = self.Processes[ProcessUnitName] or {} - - self.Processes[ProcessUnitName][ProcessName] = Process - - return Process -end --- Get the default or currently assigned @{Process} template with key ProcessName. @@ -445,35 +468,6 @@ function TASK_BASE:GetProcessTemplate( ProcessName ) 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. --- @param #TASK_BASE self --- @param #string ProcessName --- @param Process#PROCESS ProcessTemplate --- @return Process#PROCESS -function TASK_BASE:SetProcessTemplate( ProcessName, ProcessTemplate ) - - self.ProcessClasses[ProcessName] = ProcessTemplate - - return ProcessTemplate -end - - ---- Remove Processes from @{Task} with key @{Unit} --- @param #TASK_BASE self --- @param #string TaskUnitName --- @return #TASK_BASE self -function TASK_BASE:RemoveProcesses( TaskUnitName ) - self:E( TaskUnitName ) - - for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do - local Process = ProcessData -- Process.Process#PROCESS - Process:ProcessStop() - Process = nil - self.Processes[TaskUnitName][ProcessID] = nil - self:E( self.Processes[TaskUnitName][ProcessID] ) - end - self.Processes[TaskUnitName] = nil -end --- Fail processes from @{Task} with key @{Unit} -- @param #TASK_BASE self @@ -491,10 +485,10 @@ end -- @param #TASK_BASE self -- @param Unit#UNIT TaskUnit -- @return #TASK_BASE self -function TASK_BASE:AddStateMachine( TaskUnit, Fsm ) +function TASK_BASE:SetStateMachine( TaskUnit, Fsm ) local TaskUnitName = TaskUnit:GetName() - self.Fsm[TaskUnitName] = self.Fsm[TaskUnitName] or {} - self.Fsm[TaskUnitName][#self.Fsm[TaskUnitName]+1] = Fsm + self.Fsm[TaskUnitName] = Fsm + return Fsm end @@ -502,14 +496,10 @@ end -- @param #TASK_BASE self -- @param #string TaskUnitName -- @return #TASK_BASE self -function TASK_BASE:RemoveStateMachines( TaskUnitName ) +function TASK_BASE:RemoveStateMachine( TaskUnitName ) - for _, Fsm in pairs( self.Fsm[TaskUnitName] ) do - Fsm = nil - self.Fsm[TaskUnitName][_] = nil - self:E( self.Fsm[TaskUnitName][_] ) - end self.Fsm[TaskUnitName] = nil + collectgarbage() end --- Checks if there is a FiniteStateMachine assigned to @{Unit} for @{Task} @@ -609,7 +599,7 @@ end --- Gets the Scoring of the task -- @param #TASK_BASE self --- @return Scoring#SCORING Scoring +-- @return Functional.Scoring#SCORING Scoring function TASK_BASE:GetScoring() return self.Mission:GetScoring() end @@ -785,7 +775,7 @@ end -- @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 #TASK_BASE self -function TASK_BASE:AddScore( TaskStatus, ScoreText, Score ) +function TASK_BASE:AddScoreTask( TaskStatus, ScoreText, Score ) self:F2( { TaskStatus, ScoreText, Score } ) self.Scores[TaskStatus] = self.Scores[TaskStatus] or {} @@ -794,26 +784,35 @@ function TASK_BASE:AddScore( TaskStatus, ScoreText, Score ) return self end +--- Adds a score for the TASK to be achieved. +-- @param #TASK_BASE self +-- @param #string TaskStatus is the status of the TASK when the score needs to be given. +-- @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 #TASK_BASE self +function TASK_BASE:AddScoreProcess( Event, State, ScoreText, Score ) + self:F2( { State, ScoreText, Score } ) + + + self:E( self:GetFsmTemplate():GetSubs()[Event].fsm ) + local Process = self:GetFsmTemplate():GetSubs()[Event].fsm + + Process:AddScore( State, ScoreText, Score ) + + return self +end + --- StateMachine callback function for a TASK -- @param #TASK_BASE self --- @param Unit#UNIT TaskUnit -- @param StateMachine#STATEMACHINE_TASK Fsm -- @param #string Event -- @param #string From -- @param #string To -- @param Event#EVENTDATA Event -function TASK_BASE:OnAssigned( TaskUnit, Fsm, Event, From, To ) +function TASK_BASE:onenterAssigned( Fsm, Event, From, To ) self:E("Assigned") - - local TaskGroup = TaskUnit:GetGroup() - - TaskGroup:Message( self.TaskBriefing, 20 ) - - self:RemoveMenuForGroup( TaskGroup ) - self:SetAssignedMenuForGroup( TaskGroup ) - end @@ -825,19 +824,9 @@ end -- @param #string From -- @param #string To -- @param Event#EVENTDATA Event -function TASK_BASE:OnSuccess( TaskUnit, Fsm, Event, From, To ) +function TASK_BASE:onenterSuccess( TaskUnit, Fsm, Event, From, To ) self:E("Success") - - self:UnAssignFromGroups() - self:RemoveMenu() - - local TaskGroup = TaskUnit:GetGroup() - - self:StateSuccess() - - -- The task has become successful, the event catchers can be cleaned. - self:EventRemoveAll() end --- StateMachine callback function for a TASK @@ -869,17 +858,18 @@ end -- @param #string From -- @param #string To -- @param Event#EVENTDATA Event -function TASK_BASE:OnStateChange( TaskUnit, Fsm, Event, From, To ) +function TASK_BASE:onstatechange( Event, From, To ) if self:IsTrace() then MESSAGE:New( "Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll() end - self:E( { Event, From, To } ) - self:SetState( self, "State", To ) + self:E( { Event, From, To, self:IsTrace() } ) + self:E( self.Scores ) if self.Scores[To] then local Scoring = self:GetScoring() + self:E( Scoring ) if Scoring then Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score ) end diff --git a/Moose Development/Moose/Tasking/Task_SEAD.lua b/Moose Development/Moose/Tasking/Task_SEAD.lua index bb2669b5c..bd75b717f 100644 --- a/Moose Development/Moose/Tasking/Task_SEAD.lua +++ b/Moose Development/Moose/Tasking/Task_SEAD.lua @@ -67,8 +67,7 @@ do -- TASK_SEAD return nil end - - + --- Assign the @{Task} to a @{Unit}. -- @param #TASK_SEAD self @@ -85,7 +84,7 @@ do -- TASK_SEAD local FSMT = { initial = 'None', events = { - { name = 'Next', from = 'None', to = 'Planned' }, + { name = 'Start', from = 'None', to = 'Planned' }, { name = 'Next', from = 'Planned', to = 'Assigned' }, { name = 'Reject', from = 'Planned', to = 'Rejected' }, { name = 'Next', from = 'Assigned', to = 'Success' }, diff --git a/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.lua b/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.lua index 748afbd32..1aa1cf8bb 100644 --- a/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.lua +++ b/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.lua @@ -1,4 +1,6 @@ +env.info( "Lua Version = " .. _VERSION ) + local Mission = MISSION:New( 'SEAD Targets', "Strategic", "SEAD the enemy", coalition.side.RED ) local Scoring = SCORING:New( "SEAD" ) @@ -9,23 +11,32 @@ local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterOnce() local TargetZone = ZONE:New( "Target Zone" ) -local TaskSEAD = TASK_SEAD - :New( Mission, SEADSet, "SEAD Radars", TargetSet, TargetZone ) +local TaskSEAD = TASK_BASE:New( Mission, SEADSet, "SEAD Radars", "A2G", "SEAD" ) -- Tasking.Task#TASK_BASE + --:New( Mission, SEADSet, "SEAD Radars", TargetSet, TargetZone ) -TaskSEAD:AddScore( "Success", "Destroyed all target radars", 250 ) -TaskSEAD:AddScore( "Failed", "Failed to destroy all target radars", -100 ) +local FsmSEAD = TaskSEAD:GetFsmTemplate() -local AssignProcess = TaskSEAD:SetProcessTemplate( "ASSIGN", PROCESS_ASSIGN_MENU_ACCEPT:New( "SEAD", "Hello World" ) ) -AssignProcess:AddScore( TaskSEAD, "Assign", "You are assigned to the task", 10 ) +FsmSEAD:AddProcess( "Planned", "Accept", PROCESS_ASSIGN_ACCEPT:New( "SEAD the Area" ), { Assigned = "Route", Rejected = "Eject" } ) +FsmSEAD:AddProcess( "Assigned", "Route", PROCESS_ROUTE_ZONE:New( TargetZone, 3000 ), { Arrived = "Update" } ) +FsmSEAD:AddAction ( "Rejected", "Eject", "Planned" ) +FsmSEAD:AddAction ( "Arrived", "Update", "Updated" ) +FsmSEAD:AddProcess( "Updated", "Account", PROCESS_ACCOUNT_DEADS:New( TargetSet, "SEAD" ), { Accounted = "Success" } ) +FsmSEAD:AddProcess( "Updated", "Smoke", PROCESS_SMOKE_TARGETS_ZONE:New( TargetSet, TargetZone ) ) +FsmSEAD:AddAction ( "Accounted", "Success", "Success" ) +FsmSEAD:AddAction ( "Failed", "Fail", "Failed" ) -local AccountProcess = TaskSEAD:SetProcessTemplate( "ACCOUNT", PROCESS_ACCOUNT_DEADS:New( TargetSet, "SEAD" ) ) -AccountProcess:AddScore( TaskSEAD, "Account", "destroyed a radar", 25 ) -AccountProcess:AddScore( TaskSEAD, "Failed", "failed to destroy a radar", -100 ) +TaskSEAD:AddScoreTask( "Success", "Destroyed all target radars", 250 ) +TaskSEAD:AddScoreTask( "Failed", "Failed to destroy all target radars", -100 ) +TaskSEAD:AddScoreProcess( "Account", "Account", "destroyed a radar", 25 ) +TaskSEAD:AddScoreProcess( "Account", "Fail", "failed to destroy a radar", -100 ) ---local SmokeProcess = TaskSEAD:SetProcessTemplate( "SMOKE", PROCESS_SMOKE_TARGETS_ZONE:New( TargetSet, TargetZone ) ) ---SmokeProcess:SetAttackGroup( GROUP:FindByName( "SmokeGroup" ), "Watchdog" ) ---SmokeProcess:AddScore( TaskSEAD, "Account", "destroyed a radar", 25 ) ---SmokeProcess:AddScore( TaskSEAD, "Failed", "failed to destroy a radar", -100 ) +function FsmSEAD:onenterUpdated( TaskUnit ) + self:E( { self } ) + self:Account() + self:Smoke() +end +-- Needs to be checked, should not be necessary ... TaskSEAD:AssignToGroup( SEADSet:Get( "Test SEAD" ) ) +Mission:AddTask( TaskSEAD ) diff --git a/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.miz b/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.miz index 208db4352..eec018697 100644 Binary files a/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.miz and b/Moose Test Missions/Moose_Test_Tasking/Moose_Test_Task_SEAD/Moose_Test_Task_SEAD.miz differ diff --git a/Moose Training/Presentations/DCS World - MOOSE - Tasking - SEAD.pptx b/Moose Training/Presentations/DCS World - MOOSE - Tasking - SEAD.pptx index 05534866a..1b54eb9a5 100644 Binary files a/Moose Training/Presentations/DCS World - MOOSE - Tasking - SEAD.pptx and b/Moose Training/Presentations/DCS World - MOOSE - Tasking - SEAD.pptx differ