weaponstatebase.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /**@class WeaponStateBase
  2. * @brief represent weapon state base
  3. *
  4. * Class comes with entry/update/abort/exit hooks that can be overriden in custom states
  5. *
  6. * Class is ready for hierarchic composition, i.e. this state having a sub-machine running
  7. * under hood. If no m_fsm member is configured, class acts as ordinary plain
  8. * finite machine state.
  9. **/
  10. class WeaponStateBase
  11. {
  12. Weapon_Base m_weapon; /// weapon that this state relates to
  13. WeaponStateBase m_parentState; /// hierarchical parent state of this state (or null)
  14. ref WeaponFSM m_fsm; /// nested state machine (or null)
  15. int m_InternalID = -1; /// internal state id used for load/restore
  16. void WeaponStateBase (Weapon_Base w = NULL, WeaponStateBase parent = NULL) { m_weapon = w; m_parentState = parent; }
  17. /**@fn SetParentState
  18. * @brief allows construction of hierarchical state machine
  19. **/
  20. void SetParentState (WeaponStateBase parent) { m_parentState = parent; }
  21. /**@fn GetParentState
  22. * @return state that owns this sub-state (or null if plain state)
  23. **/
  24. WeaponStateBase GetParentState () { return m_parentState; }
  25. bool HasFSM () { return m_fsm != NULL; }
  26. WeaponFSM GetFSM () { return m_fsm; }
  27. void SetInternalStateID (int i) { m_InternalID = i; }
  28. int GetInternalStateID () { return m_InternalID; }
  29. bool SaveCurrentFSMState (ParamsWriteContext ctx)
  30. {
  31. if (HasFSM())
  32. {
  33. if (IsIdle())
  34. {
  35. if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::SaveCurrentFSMState - idle state, skipping other substates"); }
  36. return m_fsm.SaveCurrentFSMState(ctx);
  37. }
  38. else
  39. {
  40. // if parent state is !idle (unstable) then save whole machine
  41. if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::SaveCurrentFSMState - NOT idle state, saving full submachine state"); }
  42. return m_fsm.SaveCurrentUnstableFSMState(ctx);
  43. }
  44. return false;
  45. }
  46. return true;
  47. }
  48. bool LoadCurrentFSMState (ParamsReadContext ctx, int version)
  49. {
  50. if (HasFSM())
  51. {
  52. if (IsIdle())
  53. {
  54. if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::LoadCurrentFSMState - idle state, skipping other substates"); }
  55. if (m_fsm.LoadCurrentFSMState(ctx, version))
  56. return true;
  57. else
  58. Error("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::LoadCurrentFSMState - Cannot load stable state for weapon=" + this);
  59. }
  60. else
  61. {
  62. // if parent state is !idle (unstable) then load whole machine
  63. if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::LoadCurrentFSMState - NOT idle state, loading full submachine state"); }
  64. if (m_fsm.LoadCurrentUnstableFSMState(ctx, version))
  65. return true;
  66. else
  67. Error("[wpnfsm] " + Object.GetDebugName(m_weapon) + " WeaponStateBase::LoadCurrentFSMState - Cannot load unstable state for weapon=" + this);
  68. }
  69. return false;
  70. }
  71. return true;
  72. }
  73. bool ProcessEvent (WeaponEventBase e)
  74. {
  75. if (HasFSM())
  76. return m_fsm.ProcessEvent(e);
  77. return false;
  78. }
  79. /**@fn AddTransition
  80. * @brief adds transition into m_fsm transition table
  81. **/
  82. void AddTransition (WeaponTransition t)
  83. {
  84. if (HasFSM())
  85. m_fsm.AddTransition(t);
  86. else
  87. Error("[wpnfsm] " + Object.GetDebugName(m_weapon) + " adding transition to state without FSM. Configure FSM first.");
  88. }
  89. /**@fn OnEntry
  90. * @brief called upon entry to state
  91. * @NOTE if state has (non-running) sub-machine, it's started on entry
  92. * @param[in] e the event that triggered transition to this state
  93. **/
  94. void OnEntry (WeaponEventBase e)
  95. {
  96. if (HasFSM() && !m_fsm.IsRunning())
  97. {
  98. if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(m_weapon) + " { " + this.Type().ToString() + " Has Sub-FSM! Starting submachine..."); }
  99. m_fsm.Start(e);
  100. }
  101. else
  102. if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(m_weapon) + " { " + this.Type().ToString()); }
  103. }
  104. /**@fn OnUpdate
  105. * @brief ongoing behavior, performed while being in the state
  106. *
  107. * @NOTE: this is supposed to be the Do() operation in UML speak
  108. **/
  109. void OnUpdate (float dt)
  110. {
  111. if (HasFSM() && m_fsm.IsRunning())
  112. m_fsm.GetCurrentState().OnUpdate(dt);
  113. }
  114. /**@fn OnAbort
  115. * @brief called when abort signal arrives
  116. * @param[in] e the event that triggered abort from this state
  117. **/
  118. void OnAbort (WeaponEventBase e)
  119. {
  120. if (HasFSM() && m_fsm.IsRunning())
  121. {
  122. if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(m_weapon) + " OnAbort " + this.Type().ToString() + " Has Sub-FSM! Aborting submachine..."); }
  123. m_fsm.Abort(e);
  124. }
  125. if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(m_weapon) + " } ABORTED " + this.Type().ToString()); }
  126. }
  127. /**@fn OnExit
  128. * @brief called on exit from state
  129. * @param[in] e the event that triggered transition from this state
  130. **/
  131. void OnExit (WeaponEventBase e)
  132. {
  133. if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(m_weapon) + " } " + this.Type().ToString()); }
  134. }
  135. /**@fn IsWaitingForActionFinish
  136. * @brief waiting for active animation action/actionType finish
  137. * @return true if this state or active substate is waiting for finish signal
  138. **/
  139. bool IsWaitingForActionFinish () { return HasFSM() && m_fsm.IsRunning() && m_fsm.GetCurrentState().IsWaitingForActionFinish(); }
  140. /**@fn IsIdle
  141. * @brief idle state does not expect any animation events
  142. * @return true if this state is idle
  143. **/
  144. bool IsIdle () { return false; }
  145. /**@fn IsBoltOpen
  146. * @return true if weapon bolt is open
  147. **/
  148. bool IsBoltOpen () { return false; }
  149. /**@fn OnSubMachineChanged
  150. * @brief called when sub-machine has changed its state
  151. * @param[in] src from state (previous)
  152. * @param[in] dst to state (current)
  153. **/
  154. void OnSubMachineChanged (WeaponStateBase src, WeaponStateBase dst) { }
  155. /**@fn OnStateChanged
  156. * @brief called on current state when state machine has changed its state
  157. * @param[in] src from state (previous)
  158. * @param[in] dst to state (current)
  159. **/
  160. void OnStateChanged (WeaponStateBase src, WeaponStateBase dst) { }
  161. float GetCoolDown() { return 0; }
  162. };