From 4816cd2c57e1a85b2e76cd1c56cd279b33f54a1f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 22 Nov 2016 12:46:28 +0100 Subject: [PATCH] Got tasking working again now, with the NEW API set!!! This is really, really great! Now document all, and optimize the code. And start video making. And re-test the test mission, all... And PUBLISH!!! --- Moose Development/Moose/Core/StateMachine.lua | 169 ++++++++++++------ Moose Development/Moose/Fsm/Process.lua | 54 +----- .../Moose/Functional/Scoring.lua | 20 ++- Moose Development/Moose/Process/Account.lua | 7 +- Moose Development/Moose/Tasking/Task.lua | 71 ++++---- .../Moose_Test_Task_SEAD.lua | 17 +- .../Moose_Test_Task_SEAD.miz | Bin 25960 -> 25962 bytes 7 files changed, 185 insertions(+), 153 deletions(-) diff --git a/Moose Development/Moose/Core/StateMachine.lua b/Moose Development/Moose/Core/StateMachine.lua index 3257e8280..1344d8c03 100644 --- a/Moose Development/Moose/Core/StateMachine.lua +++ b/Moose Development/Moose/Core/StateMachine.lua @@ -41,6 +41,7 @@ function STATEMACHINE:New( options ) --self.__index = self self.options = options + self.options.subs = self.options.subs or {} self.current = options.initial or 'none' self.events = {} self.subs = {} @@ -96,6 +97,8 @@ function STATEMACHINE:AddProcess( From, Event, Process, ReturnEvents ) sub.fsm = Process sub.event = "Start" sub.ReturnEvents = ReturnEvents + + self.options.subs[Event] = sub self:_submap( self.subs, sub, nil ) @@ -145,26 +148,27 @@ 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 @@ -188,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 @@ -233,8 +237,8 @@ end function STATEMACHINE:_gosub( ParentFrom, ParentEvent ) local fsmtable = {} - self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom] } ) if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then + self:E( { ParentFrom, ParentEvent, self.subs[ParentFrom] } ) return self.subs[ParentFrom][ParentEvent] else return {} @@ -308,40 +312,6 @@ 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 @@ -385,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", @@ -408,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 @@ -452,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 5b17e1e69..4b180ea1b 100644 --- a/Moose Development/Moose/Fsm/Process.lua +++ b/Moose Development/Moose/Fsm/Process.lua @@ -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 @@ -41,63 +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 - - ---- 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.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 @@ -108,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 31514b287..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 @@ -214,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 ) @@ -226,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/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 9a5c812d8..006f74aea 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -77,7 +77,14 @@ TASK_BASE = { -- @return #TASK_BASE self function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType, TaskCategory ) - local self = BASE:Inherit( self, BASE:New() ) + + 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" ) + self:E( "New TASK " .. TaskName ) self.Processes = {} @@ -93,7 +100,8 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType, TaskCategor self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "." - self.FsmTemplate = self.FsmTemplate or STATEMACHINE_TASK:New( {}, self ) + self.FsmTemplate = self.FsmTemplate or STATEMACHINE_PROCESS:New( {} ) + self.FsmTemplate:SetTask( self ) return self end @@ -158,9 +166,10 @@ function TASK_BASE:AssignToUnit( TaskUnit ) -- Assign each FsmSub in FsmUnit to the TaskUnit. -- (This is not done during the copy). - for FsmSubID, FsmSub in ipairs( FsmUnit:GetSubs() ) do - self:E( { "Sub ID", FsmSub:GetClassNameAndID() } ) - FsmSub:Assign( self, TaskUnit ) + 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 @@ -590,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 @@ -766,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 {} @@ -775,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 @@ -806,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 @@ -850,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:T2( { 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 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 c56db1af5..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 @@ -20,19 +20,20 @@ FsmSEAD:AddProcess( "Planned", "Accept", PROCESS_ASSIGN_ACCEPT:New( "SEAD t 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" ), { Destroyed = "Success" } ) +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 ( "Destroyed", "Success", "Success" ) +FsmSEAD:AddAction ( "Accounted", "Success", "Success" ) FsmSEAD:AddAction ( "Failed", "Fail", "Failed" ) ---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( "Smoke", "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 ) function FsmSEAD:onenterUpdated( TaskUnit ) - TaskSEAD:Account() - TaskSEAD:Smoke() + self:E( { self } ) + self:Account() + self:Smoke() end -- Needs to be checked, should not be necessary ... 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 ef898521d5f7e903f9c38c0c61926728244a9934..eec01869745cbc071efc30a21d6dd06aeb494734 100644 GIT binary patch delta 11281 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