| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 | 
							- void fsmDebugPrint (string s)
 
- {
 
- #ifdef FSM_DEBUG
 
- 	PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
 
- #else
 
- 	//Print("" + s); // comment/uncomment to hide/see debug logs
 
- #endif
 
- }
 
- void fsmDebugSpam (string s)
 
- {
 
- #ifdef FSM_DEBUG_SPAM
 
- 	PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
 
- #else
 
- 	//Print("" + s); // comment/uncomment to hide/see debug logs
 
- #endif
 
- }
 
- /**@class		HFSMBase
 
-  * @brief		base class for hierarchic finite state machine
 
-  *
 
-  * stores current state (m_State) and transition table with possible transitions from each state
 
-  * to another state via event
 
-  *
 
-  * each state can have nested state machine, thus creating hierarchy
 
-  **/
 
- class HFSMBase<Class FSMStateBase, Class FSMEventBase, Class FSMActionBase, Class FSMGuardBase>
 
- {
 
- 	protected ref FSMStateBase m_State; /// current fsm state
 
- 	protected FSMStateBase m_OwnerState; /// state that owns this fsm (or null if root)
 
- 	protected ref FSMStateBase m_InitialState; /// configurable initial state of the machine
 
- 	protected ref array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>> m_Transitions = new array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>>; /// fsm transition table
 
- 	protected bool m_HasCompletions = false;
 
- 	void HFSMBase (FSMStateBase ownerState = NULL)
 
- 	{
 
- 		m_OwnerState = ownerState;
 
- 	}
 
- 	/**@fn		GetCurrentState
 
- 	 * @return	returns currently active state within this machine (i.e. not hierarchic state)
 
- 	 **/
 
- 	FSMStateBase GetCurrentState ()
 
- 	{
 
- 		return m_State;
 
- 	}
 
- 	
 
- 	/**@fn		SetCurrentState
 
- 	 * @return	returns currently active state within this machine (i.e. not hierarchic state)
 
- 	 **/
 
- 	void SetCurrentState (FSMStateBase state)
 
- 	{
 
- 		if(m_State != state)
 
- 		{
 
- 			m_State = state;
 
- 		}
 
- 	}	
 
- 	/**@fn		GetOwnerState
 
- 	 * @return	returns state that is owner of this fsm submachine. returns null if this is a root machine.
 
- 	 **/
 
- 	FSMStateBase GetOwnerState ()
 
- 	{
 
- 		return m_OwnerState;
 
- 	}
 
- 	/**@fn		GetHierarchyPath
 
- 	 * @brief		returns hierarchic state (path to root) of a state
 
- 	 * @param[in] state \p state the path is starting
 
- 	 * @param[out] path  \p  current hierarchic state
 
- 	 * @return	true if current state returned in path argument, false otherwise
 
- 	 **/
 
- 	bool GetHierarchyPath (FSMStateBase state, out array<FSMStateBase> path)
 
- 	{
 
- 		FSMStateBase curr = state;
 
- 		while (curr)
 
- 		{
 
- 		  path.Insert(curr);
 
- 		  curr = curr.GetParentState();
 
- 		}
 
- 		return path.Count() > 0;
 
- 	}
 
- 	/**@fn		SetInitialState
 
- 	 * @param[in] initial_state \p state the machine will be entered to after ::Start()
 
- 	 * @param[in] initial_event \p event that will be used to start the machine
 
- 	 **/
 
- 	void SetInitialState (FSMStateBase initial_state)
 
- 	{
 
- 		m_InitialState = initial_state;
 
- 	}
 
- 	/**@fn		AddTransition
 
- 	 * @brief	adds transition into transition table
 
- 	 **/
 
- 	void AddTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t)
 
- 	{
 
- 		m_Transitions.Insert(t);
 
- 		//if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] +++ ow=" + this.GetOwnerState() + " this=" + this + " t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
 
- 		if (t.m_event == NULL)
 
- 		{
 
- 			Print("Warning (performance): FSM " + this + " has completion transition for src=" + t.m_srcState + " ---NULL----|> dst=" + t.m_dstState);
 
- 			m_HasCompletions = true;
 
- 		}
 
- 	}
 
- 	/**@fn		Start
 
- 	 * @brief	starts the state machine by entering the initial_state (using intial_event as argument to initial state's onEntry)
 
- 	 * @param[in] e \p optional event for starting the machind
 
- 	 **/
 
- 	void Start (FSMEventBase initial_event = NULL, bool useExistingState = false)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			fsmDebugPrint("[hfsm] " + this.ToString() + "::Start(" + initial_event.ToString() + "), init_state=" + m_InitialState.ToString());
 
- 		}
 
- 			
 
- 		if (!useExistingState)
 
- 			m_State = m_InitialState;
 
- 		
 
- 		m_State.OnEntry(initial_event);
 
- 		
 
- 		if (m_HasCompletions)
 
- 			ProcessCompletionTransitions();
 
- 	}
 
- 	/**@fn		IsRunning
 
- 	 * @brief	returns true if machine is in running state
 
- 	 **/
 
- 	bool IsRunning () { return m_State != NULL; }
 
- 	/**@fn		Terminate
 
- 	 * @brief	terminates the state machine
 
- 	 **/
 
- 	void Terminate (FSMEventBase terminal_event = NULL)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			fsmDebugPrint("[hfsm] " + this.ToString() + "::Terminate(" + terminal_event.ToString() + ")");
 
- 		}
 
- 		
 
- 		if (IsRunning())
 
- 		{
 
- 			m_State.OnExit(terminal_event);
 
- 			m_State = NULL;
 
- 		}
 
- 	}
 
- 	void Abort (FSMEventBase abort_event = NULL)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			fsmDebugPrint("[hfsm] " + this.ToString() + "::Abort(" + abort_event.ToString() + ")");
 
- 		}
 
- 			
 
- 		if (IsRunning())
 
- 		{
 
- 			m_State.OnAbort(abort_event);
 
- 			m_State = NULL;
 
- 		}
 
- 	}
 
- 	/**@fn		Update
 
- 	 * @brief	if machine running, call OnUpdate() on current state
 
- 	 **/
 
- 	void Update (float dt)
 
- 	{
 
- 		if (IsRunning())
 
- 			m_State.OnUpdate(dt);
 
- 	}
 
- 	protected ProcessEventResult ProcessAbortTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			fsmDebugPrint("[hfsm] (local abort) state=" + t.m_srcState.ToString() + "-------- ABORT event=" + e.ToString() + "[G=" + t.m_guard.ToString() +"]/A=" + t.m_action.ToString() + " --------|> dst=" + t.m_dstState.ToString());
 
- 		}
 
- 		
 
- 		m_State.OnAbort(e);			// 1) call onAbort on old state
 
- 		if (t.m_action)
 
- 			t.m_action.Action(e);	// 2) execute transition action (if any)
 
- 		auto tmp = t.m_srcState.GetParentState();
 
- 		if (tmp == t.m_dstState.GetParentState())
 
- 		{
 
- 			m_State = t.m_dstState;		// 3) change state to new (or NULL)
 
- 			if (t.m_dstState != NULL)
 
- 			{
 
- 				m_State.OnEntry(e);		// 4a1) call onEntry on new state (see 4a2) )
 
- 				return ProcessEventResult.FSM_OK;
 
- 			}
 
- 			else
 
- 			{
 
- 				if (LogManager.IsInventoryHFSMLogEnable())
 
- 				{
 
- 					fsmDebugPrint("[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
 
- 				}
 
- 					
 
- 				return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
 
- 			}
 
- 		}
 
- 		else
 
- 		{
 
- 			m_State = NULL;
 
- 			return ProcessEventResult.FSM_ABORTED; // 4c) or signal abort to parent (with appropriate transition)
 
- 		}
 
- 	}
 
- 	/**@fn		FindAbortDestinationState
 
- 	 * @brief	i
 
- 	 * @param[in]	e	\p	event that will be used to find suitable transition from current state
 
- 	 * @return	FSM_OK if transition found and allowed by guard (if any)
 
- 	 * @return	FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
 
- 	 * @return	FSM_TERMINATED state machine has terminated
 
- 	 * @return	FSM_ABORTED state machine has aborted
 
- 	 **/
 
- 	FSMStateBase FindAbortDestinationState (FSMEventBase e)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			if (GetOwnerState())
 
- 				fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::FindAbortDestinationState(" + e.Type().ToString() + ")");
 
- 			else
 
- 				fsmDebugPrint("[hfsm] root::FindAbortDestinationState(" + e.Type().ToString() + ")");
 
- 		}
 
- 		
 
- 		// 1) look in submachine first (if any)
 
- 		if (m_State && m_State.HasFSM())
 
- 		{
 
- 			HFSMBase<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> a = m_State.GetFSM();
 
- 			FSMStateBase abort_dst = a.FindAbortDestinationState(e);
 
- 			if (abort_dst)
 
- 			{
 
- 				return abort_dst;
 
- 			}
 
- 		}
 
- 		// 2) local transitions
 
- 		int i = FindFirstUnguardedTransition(e);
 
- 		if (i == -1)
 
- 		{
 
- 			if (LogManager.IsInventoryHFSMLogEnable())
 
- 			{
 
- 				fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
 
- 			}
 
- 			
 
- 			return NULL;
 
- 		}
 
- 		FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 		return t.m_dstState;
 
- 	}
 
- 	
 
- 	/**@fn		ProcessAbortEvent
 
- 	 * @brief	instructs the hierarchical state machine to process the event e
 
- 	 * @param[in]	e	\p	event that will be used to find suitable transition from current state
 
- 	 * @return	FSM_OK if transition found and allowed by guard (if any)
 
- 	 * @return	FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
 
- 	 * @return	FSM_TERMINATED state machine has terminated
 
- 	 * @return	FSM_ABORTED state machine has aborted
 
- 	 **/
 
- 	FSMStateBase ProcessAbortEvent(FSMEventBase e, out ProcessEventResult result)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			if (GetOwnerState())
 
- 				fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::ProcessAbortEvent(" + e.Type().ToString() + ")");
 
- 			else
 
- 				fsmDebugPrint("[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + ")");
 
- 		}
 
- 		
 
- 		// 1) look in submachine first (if any)
 
- 		if (m_State && m_State.HasFSM())
 
- 		{
 
- 			HFSMBase<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> a = m_State.GetFSM();
 
- 			ProcessEventResult subfsm_res;
 
- 			FSMStateBase abort_dst = a.ProcessAbortEvent(e, subfsm_res);
 
- 			switch (subfsm_res)
 
- 			{
 
- 				case ProcessEventResult.FSM_OK:
 
- 				{
 
- 					if (LogManager.IsInventoryHFSMLogEnable())
 
- 					{
 
- 						fsmDebugPrint("[hfsm] event processed by sub machine=" + m_State.ToString());
 
- 					}
 
- 					result = subfsm_res;		// 1.1) submachine accepted event
 
- 					return NULL;
 
- 				}
 
- 				case ProcessEventResult.FSM_ABORTED:
 
- 				{
 
- 					if (LogManager.IsInventoryHFSMLogEnable())
 
- 					{
 
- 						fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString());
 
- 					}
 
- 					m_State.OnAbort(e); // 1.2) submachine aborted, abort submachine owner (i.e. this)
 
- 					if (GetOwnerState() == abort_dst.GetParentState())
 
- 					{
 
- 						if (LogManager.IsInventoryHFSMLogEnable())
 
- 						{
 
- 							fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " & abort destination reached.");
 
- 						}
 
- 						m_State = abort_dst;
 
- 						m_State.OnEntry(e);		// 1.3) submachine aborted, call onEntry on new state (cross-hierarchy transition)
 
- 						result = ProcessEventResult.FSM_OK;
 
- 						return NULL;
 
- 					}
 
- 					else
 
- 					{
 
- 						result = ProcessEventResult.FSM_ABORTED; // 1.4) submachine has aborted, look for destination state in parent
 
- 						return NULL;
 
- 					}
 
- 					break;
 
- 				}
 
- 				case ProcessEventResult.FSM_TERMINATED:
 
- 				{
 
- 					break; // submachine has finished, look for local transitions from exited submachine
 
- 				}
 
- 				case ProcessEventResult.FSM_NO_TRANSITION:
 
- 				{
 
- 					if (LogManager.IsInventoryHFSMLogEnable())
 
- 					{
 
- 						fsmDebugPrint("[hfsm] aborted (but no transition) sub machine=" + m_State.ToString());
 
- 					}
 
- 					break; // submachine has no transition, look for transitions in local machine
 
- 				}
 
- 			}
 
- 		}
 
- 		// 2) local transitions
 
- 		int i = FindFirstUnguardedTransition(e);
 
- 		if (i == -1)
 
- 		{
 
- 			if (LogManager.IsInventoryHFSMLogEnable())
 
- 			{
 
- 				fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
 
- 			}
 
- 			result = ProcessEventResult.FSM_NO_TRANSITION;
 
- 			return NULL;
 
- 		}
 
- 		FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 		ProcessEventResult res = ProcessAbortTransition(t, e);
 
- 		result = res;
 
- 		switch (res)
 
- 		{
 
- 			case ProcessEventResult.FSM_OK:
 
- 			{
 
- 				//if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] abort event processed by machine=" + m_State.ToString());
 
- 				return NULL; // machine accepted event
 
- 			}
 
- 			case ProcessEventResult.FSM_ABORTED:
 
- 			{
 
- 				if (LogManager.IsInventoryHFSMLogEnable())
 
- 				{
 
- 					fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " will fall-through to dst=" + t.m_dstState);
 
- 				}
 
- 				return t.m_dstState; // store destination state for parent(s)
 
- 			}
 
- 			case ProcessEventResult.FSM_TERMINATED:
 
- 			{
 
- 				if (LogManager.IsInventoryHFSMLogEnable())
 
- 				{
 
- 					fsmDebugPrint("[hfsm] aborted & terminated sub machine=" + m_State.ToString());
 
- 				}
 
- 				break; // submachine has finished, look for local transitions from exited submachine
 
- 			}
 
- 			case ProcessEventResult.FSM_NO_TRANSITION:
 
- 			{	
 
- 				break; // submachine has no transition, look for transitions in local machine
 
- 			}
 
- 		}
 
- 		return NULL;
 
- 	}
 
- 	/**@fn		ProcessEvent
 
- 	 * @brief	instructs the hierarchical state machine to process the event e
 
- 	 * @param[in]	e	\p	event that will be used to find suitable transition from current state
 
- 	 * @return	FSM_OK if transition found and allowed by guard (if any)
 
- 	 * @return	FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
 
- 	 * @return	FSM_TERMINATED state machine has terminated
 
- 	 **/
 
- 	ProcessEventResult ProcessEvent(FSMEventBase e)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			if (GetOwnerState())
 
- 				fsmDebugPrint("[hfsm] SUB!::" + GetOwnerState().Type().ToString() + "::ProcessEvent(" + e.Type().ToString() + ")");
 
- 			else
 
- 				fsmDebugPrint("[hfsm] root::ProcessEvent(" + e.Type().ToString() + " =" + e.DumpToString());
 
- 		}
 
- 		
 
- 		// 1) completion transitions have priority (if any)
 
- 		if (m_HasCompletions)
 
- 			ProcessCompletionTransitions();
 
- 		// 2) submachine then (if any)
 
- 		if (m_State && m_State.HasFSM())
 
- 		{
 
- 			ProcessEventResult subfsm_res = m_State.ProcessEvent(e);
 
- 			switch (subfsm_res)
 
- 			{
 
- 				case ProcessEventResult.FSM_OK:
 
- 				{
 
- 					if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] event processed by sub machine=" + m_State.ToString());
 
- 					return subfsm_res; // submachine accepted event
 
- 				}
 
- 				case ProcessEventResult.FSM_TERMINATED:
 
- 				{
 
- 					break; // submachine has finished, look for local transitions from exited submachine
 
- 				}
 
- 				case ProcessEventResult.FSM_NO_TRANSITION:
 
- 				{	
 
- 					break; // submachine has no transition, look for transitions in local machine
 
- 				}
 
- 			}
 
- 		}
 
- 		// 3) local transitions
 
- 		int i = FindFirstUnguardedTransition(e);
 
- 		if (i == -1)
 
- 		{
 
- 			if (LogManager.IsInventoryHFSMLogEnable())
 
- 			{
 
- 				fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
 
- 			}
 
- 			return ProcessEventResult.FSM_NO_TRANSITION;
 
- 		}
 
- 		FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(i);
 
- 		ProcessEventResult res;
 
- 		if (row.m_dstState != NULL)
 
- 		{
 
- 			// this is regular transition
 
- 			if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
 
- 				res = LocalTransition(i, e); // transition is within this state machine
 
- 			else
 
- 				Error("cross-hierarchy transition or misconfigured transition detected!");
 
- 				//res = HierarchicTransition(i, e); // transition has to cross hierarchy
 
- 		}
 
- 		else
 
- 		{
 
- 			// this is terminating transition
 
- 			if (row.m_srcState.GetParentState() == GetOwnerState())
 
- 				res = LocalTransition(i, e); // terminating transition is within this state machine
 
- 			else
 
- 				Error("cross-hierarchy transition or misconfigured transition detected!");
 
- 				//res = HierarchicTransition(i, e); // source node crosses hierarchy (terminate lies always within this machine)
 
- 		}
 
- 		return res;
 
- 	}
 
- 	protected int FindFirstUnguardedTransition (FSMEventBase e)
 
- 	{
 
- 		FSMStateBase curr_state = m_State;
 
- 		int count = m_Transitions.Count();
 
- 		for (int i = 0; i < count; ++i)
 
- 		{
 
- 			FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 			if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
 
- 			{
 
- 				//if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] [" + i + "/" + count + "] *** matched! t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
 
- 				bool hasGuard = t.m_guard != NULL;
 
- 				if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e)))		// 1) exec guard (if any)
 
- 				{
 
- 					return i;
 
- 				}
 
- 			}
 
- 			//else if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm][" + i + "/" + count + "] ... matching  t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
 
- 		}
 
- 		return -1;
 
- 	}
 
- 	
 
- 	FSMStateBase FindTransitionState(FSMStateBase s, FSMEventBase e)
 
- 	{
 
- 		FSMStateBase curr_state = s;
 
- 		int count = m_Transitions.Count();
 
- 		for (int i = 0; i < count; ++i)
 
- 		{
 
- 			FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 			if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
 
- 			{
 
- 				return t.m_dstState;
 
- 			}
 
- 		}
 
- 		return null;
 
- 	}
 
- 	
 
- 	FSMStateBase FindGuardedTransitionState(FSMStateBase s, FSMEventBase e)
 
- 	{
 
- 		FSMStateBase curr_state = s;
 
- 		int count = m_Transitions.Count();
 
- 		for (int i = 0; i < count; ++i)
 
- 		{
 
- 			FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 			if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
 
- 			{
 
- 				bool hasGuard = t.m_guard != NULL;
 
- 				if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e)))		// 1) exec guard (if any)
 
- 				{
 
- 					return t.m_dstState;
 
- 				}
 
- 			}
 
- 		}
 
- 		return null;
 
- 	}
 
- 	protected int FindFirstCompletionTransition ()
 
- 	{
 
- 		if (IsRunning())
 
- 		{
 
- 			FSMStateBase curr_state = m_State;
 
- 			int count = m_Transitions.Count();
 
- 			for (int i = 0; i < count; ++i)
 
- 			{
 
- 				FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 				//if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] (local) matching state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
 
- 				if ((t.m_srcState.Type() == curr_state.Type()) && (t.m_event == NULL))
 
- 				{
 
- 					bool hasGuard = t.m_guard != NULL;
 
- 					if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(NULL)))		// 1) exec guard (if any)
 
- 					{
 
- 						return i;
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 		return -1;
 
- 	}
 
- 	/**@fn		ProcessLocalTransition
 
- 	 * @brief	instructs the state machine to process the event locally - no hierarchy is crossed
 
- 	 * @param[in]	t	\p	the transition in m_Transitions
 
- 	 * @param[in]	e	\p	event that will be used to process transition from current state
 
- 	 * @return	FSM_OK or FSM_TERMINATED
 
- 	 **/
 
- 	protected ProcessEventResult ProcessLocalTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
 
- 	{
 
- 		if (LogManager.IsInventoryHFSMLogEnable())
 
- 		{
 
- 			fsmDebugPrint("[hfsm] (local) state=" + t.m_srcState.ToString() + "-------- event=" + e.ToString() + "[G=" + t.m_guard.ToString() +"]/A=" + t.m_action.ToString() + " --------|> dst=" + t.m_dstState.ToString());
 
- 		}
 
- 		
 
- 		m_State.OnExit(e);			// 1) call onExit on old state
 
- 		if (t.m_action)
 
- 			t.m_action.Action(e);	// 2) execute transition action (if any)
 
- 		m_State = t.m_dstState;		// 3) change state to new
 
- 		if (t.m_dstState != NULL)
 
- 		{
 
- 			m_State.OnEntry(e);		// 4a) call onEntry on new state
 
- 			if (GetOwnerState())
 
- 				GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState);	// 5a) notify owner state about change in submachine
 
- 			
 
- 			if (m_State)
 
- 				m_State.OnStateChanged(t.m_srcState, t.m_dstState); // 5b) notify current state about change in machine
 
- 			return ProcessEventResult.FSM_OK;
 
- 		}
 
- 		else
 
- 		{
 
- 			if (LogManager.IsInventoryHFSMLogEnable())
 
- 			{
 
- 				fsmDebugPrint("[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
 
- 			}
 
- 				
 
- 			if (GetOwnerState())
 
- 				GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL);	// 5) notify owner state about change in submachine
 
- 			return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
 
- 		}
 
- 	}
 
- 	/**@fn		LocalProcessEvent
 
- 	 * @brief	instructs the state machine to process the event e
 
- 	 * @param[in]	i	\p	index of the transition in m_Transitions
 
- 	 * @param[in]	e	\p	event that will be used to process transition from current state
 
- 	 * @return	FSM_OK or FSM_TERMINATED
 
- 	 **/
 
- 	protected ProcessEventResult LocalTransition (int i, FSMEventBase e)
 
- 	{
 
- 		FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 		ProcessEventResult ret = ProcessLocalTransition(t, e);
 
- 		return ret;
 
- 	}
 
- 	protected ProcessEventResult ProcessCompletionTransitions ()
 
- 	{
 
- 		int completionIdx = FindFirstCompletionTransition();
 
- 		while (completionIdx != -1)
 
- 		{
 
- 			FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(completionIdx);
 
- 			ProcessEventResult res;
 
- 			if (row.m_dstState != NULL)
 
- 			{
 
- 				// this is regular completion transition
 
- 				if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
 
- 					res = LocalTransition(completionIdx, NULL); // transition is within this state machine
 
- 				else
 
- 					Error("cross-hierarchy transition or misconfigured transition detected!");
 
- 					//res = HierarchicTransition(completionIdx, NULL); // transition has to cross hierarchy
 
- 			}
 
- 			else
 
- 			{
 
- 				// this is terminating completion transition
 
- 				if (row.m_srcState.GetParentState() == GetOwnerState())
 
- 					res = LocalTransition(completionIdx, NULL); // terminating transition is within this state machine
 
- 				else
 
- 					Error("cross-hierarchy transition or misconfigured transition detected!");
 
- 					//res = HierarchicTransition(completionIdx, NULL); // source node crosses hierarchy (terminate lies always within this machine)
 
- 			}
 
- 			completionIdx = FindFirstCompletionTransition();
 
- 		}
 
- 		return ProcessEventResult.FSM_NO_TRANSITION;
 
- 	}
 
- };
 
- /** cross-hierarchy transitions (for future use):
 
- 	protected bool RemoveCommonParents (out array<WeaponStateBase> src_path, out array<WeaponStateBase> dst_path)
 
- 	{
 
- 		//for (int j = 0; j < src_path.Count(); ++j) fsmDebugPrint("[hfsm] curr state src_path[" + j + "] = " + src_path[j].ToString());
 
- 		//for (int k = 0; k < dst_path.Count(); ++k) fsmDebugPrint("[hfsm] next state dst_path[" + k + "] = " + dst_path[k].ToString());
 
- 		while ((src_path.Count() > 0) && (dst_path.Count() > 0) && (src_path.Get(src_path.Count() - 1) == dst_path.Get(dst_path.Count() - 1)))
 
- 		{
 
- 			src_path.Remove(src_path.Count() - 1);
 
- 			dst_path.Remove(dst_path.Count() - 1);
 
- 		}
 
- 		//for (int je = 0; je < src_path.Count(); ++je) fsmDebugPrint("[hfsm] curr state src_path[" + je + "] = " + src_path[je].ToString());
 
- 		//for (int ke = 0; ke < dst_path.Count(); ++ke) fsmDebugPrint("[hfsm] next state dst_path[" + ke + "] = " + dst_path[ke].ToString());
 
- 	}
 
- 	protected ProcessEventResult HierarchicTransition (int i, FSMEventBase e)
 
- 	{
 
- 		fsmDebugPrint("[hfsm] { " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ")");
 
- 		FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
 
- 		array<WeaponStateBase> src_path = new array<WeaponStateBase>;
 
- 		array<WeaponStateBase> dst_path = new array<WeaponStateBase>;
 
- 		if (GetHierarchyPath(t.m_srcState, src_path))
 
- 		{
 
- 			if (t.m_dstState == NULL)
 
- 			{
 
- 				Error("cross hierarchy terminate not yet implemented");
 
- 				WeaponStateBase curr_state = GetCurrentState();
 
- 				//for (int ex = 0; ex < src_path.Count(); ++ex) { fsmDebugPrint("[hfsm] exiting level=" + ex); src_path[ex].OnExit(e); }
 
- 				//for (int en = dst_path.Count(); en --> 0;)
 
- 				//for (int en = 0; en < dst_path.Count(); ++en) { fsmDebugPrint("[hfsm] entering level=" + en); int ii = dst_path.Count() - 1 - en; dst_path[ii].OnEntry(e); }
 
- 				fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> terminated");
 
- 				return ProcessEventResult.FSM_TERMINATED;
 
- 			}
 
- 			else if (GetHierarchyPath(t.m_dstState, dst_path))
 
- 			{
 
- 				Error("cross hierarchy event implemented, not fully debugged");
 
- 				RemoveCommonParents(src_path, dst_path);
 
- 				for (int ex = 0; ex < src_path.Count(); ++ex)
 
- 				{
 
- 					src_path[ex].OnExit(e); // 1) call OnExit on all nodes on src_path ()
 
- 				}
 
- 				//if (t.m_action)
 
- 				//	t.m_action.Action(e);	// 2) execute transition action (if any)
 
- 				//m_State = t.m_dstState; // 4) change state to new
 
- 				
 
- 				//for (int en = dst_path.Count(); en --> 0;)
 
- 				for (int en = 0; en < dst_path.Count(); ++en)
 
- 				{
 
- 					int ii = dst_path.Count() - 1 - en;
 
- 					dst_path[ii].OnEntry(e);	// 5) call OnEntry on all nodes on dst_path (@NOTE: reverse order)
 
- 				}
 
- 				fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> OK");
 
- 				return ProcessEventResult.FSM_OK;
 
- 			}
 
- 			else
 
- 			{
 
- 				Error("unhandled case, what did you do?");
 
- 			}
 
- 		}
 
- 		fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> no transition");
 
- 		return ProcessEventResult.FSM_NO_TRANSITION;
 
- 	}
 
- */
 
 
  |