/**@class HandStateBase * @brief represent hand state base * * Class comes with entry/update/exit hooks that can be overriden in custom states **/ class HandStateBase { Man m_Player; /// entity that this state relates to HandStateBase m_parentState; /// hierarchical parent state of this state (or null) ref HandFSM m_FSM; /// nested state machine (or null) void HandStateBase (Man player = NULL, HandStateBase parent = NULL) { m_Player = player; m_parentState = parent; } /**@fn SetParentState * @brief allows construction of hierarchical state machine **/ void SetParentState (HandStateBase parent) { m_parentState = parent; } /**@fn GetParentState * @return state that owns this sub-state (or null if plain state) **/ HandStateBase GetParentState () { return m_parentState; } bool HasFSM () { return m_FSM != NULL; } HandFSM GetFSM () { return m_FSM; } bool ProcessEvent (HandEventBase e) { if (HasFSM()) return m_FSM.ProcessEvent(e); return false; } /**@fn AddTransition * @brief adds transition into m_FSM transition table **/ void AddTransition (HandTransition t) { if (HasFSM()) m_FSM.AddTransition(t); else Error("[hndfsm] adding transition to state without FSM. Configure FSM first."); } /**@fn OnEntry * @brief called upon entry to state * @NOTE if state has (non-running) sub-machine, it's started on entry * @param[in] e the event that triggered transition to this state **/ void OnEntry (HandEventBase e) { if (HasFSM() && !m_FSM.IsRunning()) { if (e) { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] { " + Object.GetDebugName(e.m_Player) + " STS = " + e.m_Player.GetSimulationTimeStamp() + " " + this.Type().ToString() + " Has Sub-FSM! Starting submachine..."); } else { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] { " + this.Type().ToString() + " Has Sub-FSM! Starting submachine..."); } m_FSM.Start(e); } else { if (e) { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] { " + Object.GetDebugName(e.m_Player) + " STS = " + e.m_Player.GetSimulationTimeStamp() + " " + this.Type().ToString()); } else { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] { " + this.Type().ToString()); } } } /**@fn OnUpdate * @brief ongoing behavior, performed while being in the state * * @NOTE: this is supposed to be the Do() operation in UML speak **/ void OnUpdate (float dt) { if (HasFSM() && m_FSM.IsRunning()) m_FSM.GetCurrentState().OnUpdate(dt); } /**@fn OnAbort * @brief called when abort signal arrives * @param[in] e the event that triggered abort from this state **/ void OnAbort (HandEventBase e) { if (HasFSM() && m_FSM.IsRunning()) { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] OnAbort " + this.Type().ToString() + " Has Sub-FSM! Aborting submachine..."); m_FSM.Abort(e); } //Debug.InventoryHFSMLog("ABORTED " + e.m_Player.GetSimulationTimeStamp(), ""/*typename.EnumToString(HandEventID, GetEventID()) */, "n/a", "OnAbort", m_Player.ToString() ); if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] } " + Object.GetDebugName(e.m_Player) + " STS = " + e.m_Player.GetSimulationTimeStamp() + " ABORTED " + this.Type().ToString()); } /**@fn OnExit * @brief called on exit from state * @param[in] e the event that triggered transition from this state **/ void OnExit (HandEventBase e) { if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[hndfsm] } " + Object.GetDebugName(e.m_Player) + " STS = " + e.m_Player.GetSimulationTimeStamp() + " " + this.Type().ToString()); } /**@fn IsWaitingForActionFinish * @brief waiting for active animation action/actionType finish * @return true if this state is waiting for finish signal **/ bool IsWaitingForActionFinish () { return HasFSM() && m_FSM.IsRunning() && m_FSM.GetCurrentState().IsWaitingForActionFinish(); } /**@fn IsIdle * @brief idle state does not expect any animation events * @return true if this state is idle **/ bool IsIdle () { return false; } /**@fn OnSubMachineChanged * @brief called when sub-machine has changed its state * @param[in] src from state (previous) * @param[in] dst to state (current) **/ void OnSubMachineChanged (HandStateBase src, HandStateBase dst) { } /**@fn OnStateChanged * @brief called on current state when state machine has changed its state * @param[in] src from state (previous) * @param[in] dst to state (current) **/ void OnStateChanged (HandStateBase src, HandStateBase dst) { m_Player.GetHumanInventory().OnHandsStateChanged(src, dst); } };