statemachine.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : combat *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/statemachine.h $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 11/07/01 5:27p $*
  29. * *
  30. * $Revision:: 4 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #if defined(_MSC_VER)
  36. #pragma once
  37. #endif
  38. #ifndef __STATEMACHINE_H
  39. #define __STATEMACHINE_H
  40. #include "simplevec.h"
  41. #include "chunkio.h"
  42. //////////////////////////////////////////////////////////////////////
  43. // Macros
  44. //////////////////////////////////////////////////////////////////////
  45. //#define ADD_STATE_TO_MACHINE(machine, state) \
  46. //machine.Add_State (On_##state_Think, On_##state_Request_End, On_##state_Begin, On_##state_End);
  47. /*#define ADD_STATE_TO_MACHINE(machine, state, is_think, is_request_end, is_begin, is_end) \
  48. machine.Add_State ( \
  49. is_think ? On_##state##_Think : NULL, \
  50. is_request_end ? On_##state##_Request_End : NULL, \
  51. is_begin ? On_##state##_Begin : NULL, \
  52. is_end ? On_##state##_End : NULL); */
  53. #define ADD_STATE_TO_MACHINE(machine, state) \
  54. machine.Add_State ( \
  55. On_##state##_Think, \
  56. On_##state##_Request_End, \
  57. On_##state##_Begin, \
  58. On_##state##_End);
  59. //machine.Add_State (On_##state_Think, On_##state_Request_End, On_##state_Begin, On_##state_End);
  60. /*#define BEGIN_STATE_MAP(machine) \
  61. void Install_##machine_States (void) { \
  62. #define ADD_STATE_HANDLER(machine, state) \
  63. machine.Add_State (state); \
  64. machine.
  65. #define END_STATE_MAP() \
  66. }*/
  67. //#define ADD_STATE_TO_MACHINE(machine, state) \
  68. //machine.Add_State (On_##state_Think, On_##state_Request_End, On_##state_Begin, On_##state_End);
  69. /*#define DECLARE_STATE_HANDLER(state) \
  70. void On_##state##_Begin (void); \
  71. void On_##state##_End (void); \
  72. void On_##state##_Think (void); \
  73. bool On_##state##_Request_End (int new_state);*/
  74. #define SM_BEGIN ;
  75. #define SM_END ;
  76. #define SM_THINK ;
  77. #define SM_REQ_END ;
  78. #define SM_NO_BEGIN {}
  79. #define SM_NO_END {}
  80. #define SM_NO_THINK {}
  81. #define SM_NO_REQ_END { return true; }
  82. #define DECLARE_STATE(state, begin, end, think, req_end) \
  83. void On_##state##_Begin (void) begin \
  84. void On_##state##_End (void) end \
  85. void On_##state##_Think (void) think \
  86. bool On_##state##_Request_End (int state) req_end
  87. #define DECLARE_STATE_HANDLER_BEGIN(state) \
  88. void On_##state##_Begin (void)
  89. #define DECLARE_STATE_HANDLER_END(state) \
  90. void On_##state##_End (void)
  91. #define DECLARE_STATE_HANDLER_THINK(state) \
  92. void On_##state##_Think (void)
  93. #define DECLARE_STATE_HANDLER_REQUEST_END(state) \
  94. bool On_##state##_Request_End (int state)
  95. #define STATE_IMPL_BEGIN(state) \
  96. On_##state##_Begin
  97. #define STATE_IMPL_END(state) \
  98. On_##state##_End
  99. #define STATE_IMPL_THINK(state) \
  100. On_##state##_Think
  101. #define STATE_IMPL_REQUEST_END(state) \
  102. On_##state##_Request_End
  103. /*#define DECLARE_STATE_HANDLER_BEGIN(state) \
  104. void On_##state_Begin (void);
  105. #define DECLARE_STATE_HANDLER_END(state) \
  106. void On_##state_End (void);
  107. #define DECLARE_STATE_HANDLER_THINK(state) \
  108. void On_##state_Think (void);
  109. #define DECLARE_STATE_HANDLER_REQUEST_END(state) \
  110. void On_##state_Request_End (void);
  111. */
  112. //////////////////////////////////////////////////////////////////////
  113. //
  114. // StateClass
  115. //
  116. //////////////////////////////////////////////////////////////////////
  117. template <class T>
  118. class StateClass
  119. {
  120. public:
  121. ///////////////////////////////////////////////////////////////////
  122. // Public constructors/destructors
  123. ///////////////////////////////////////////////////////////////////
  124. StateClass<T> (void) :
  125. Think (NULL),
  126. RequestEnd (NULL),
  127. Begin (NULL),
  128. End (NULL) {}
  129. ///////////////////////////////////////////////////////////////////
  130. // Public typedefs
  131. ///////////////////////////////////////////////////////////////////
  132. typedef void (T::*THINK_PTR) (void);
  133. typedef bool (T::*REQUEST_END_PTR) (int new_state);
  134. typedef void (T::*BEGIN_PTR) (void);
  135. typedef void (T::*END_PTR) (void);
  136. ///////////////////////////////////////////////////////////////////
  137. // Public member data
  138. ///////////////////////////////////////////////////////////////////
  139. THINK_PTR Think;
  140. REQUEST_END_PTR RequestEnd;
  141. BEGIN_PTR Begin;
  142. END_PTR End;
  143. };
  144. //////////////////////////////////////////////////////////////////////
  145. //
  146. // StateMachineClass
  147. //
  148. //////////////////////////////////////////////////////////////////////
  149. template <class T>
  150. class StateMachineClass
  151. {
  152. public:
  153. ///////////////////////////////////////////////////////////////////
  154. // Public typedefs
  155. ///////////////////////////////////////////////////////////////////
  156. typedef StateClass<T> STATE_OBJ;
  157. ///////////////////////////////////////////////////////////////////
  158. // Save/load constants
  159. ///////////////////////////////////////////////////////////////////
  160. enum
  161. {
  162. CHUNKID_VARIABLES = 0x11070946,
  163. VARID_CURR_STATE = 0,
  164. VARID_IS_HALTED,
  165. };
  166. ///////////////////////////////////////////////////////////////////
  167. // Public constructors/destructors
  168. ///////////////////////////////////////////////////////////////////
  169. StateMachineClass (T *object) :
  170. CurrState (-1),
  171. Object (object),
  172. IsHalted (false) {}
  173. virtual ~StateMachineClass (void) {}
  174. ///////////////////////////////////////////////////////////////////
  175. // Public methods
  176. ///////////////////////////////////////////////////////////////////
  177. ///////////////////////////////////////////////////////////////////
  178. // Think
  179. ///////////////////////////////////////////////////////////////////
  180. void Think (void)
  181. {
  182. if (IsHalted) {
  183. return ;
  184. }
  185. //
  186. // Call the think member function of the container
  187. //
  188. if (Is_Valid_State (CurrState)) {
  189. if (StateTable[CurrState].Think != NULL) {
  190. (Object->*(StateTable[CurrState].Think)) ();
  191. }
  192. }
  193. return ;
  194. }
  195. ///////////////////////////////////////////////////////////////////
  196. // Add_State
  197. ///////////////////////////////////////////////////////////////////
  198. void Add_State (StateClass<T> &state)
  199. {
  200. StateTable.Add (state);
  201. return ;
  202. }
  203. ///////////////////////////////////////////////////////////////////
  204. // Add_State
  205. ///////////////////////////////////////////////////////////////////
  206. void Add_State
  207. (
  208. STATE_OBJ::THINK_PTR think_ptr,
  209. STATE_OBJ::REQUEST_END_PTR request_ptr,
  210. STATE_OBJ::BEGIN_PTR begin_ptr,
  211. STATE_OBJ::END_PTR end_ptr
  212. )
  213. {
  214. StateClass<T> state;
  215. state.Think = think_ptr;
  216. state.RequestEnd = request_ptr;
  217. state.Begin = begin_ptr;
  218. state.End = end_ptr;
  219. Add_State (state);
  220. return ;
  221. }
  222. ///////////////////////////////////////////////////////////////////
  223. // Halt_State
  224. ///////////////////////////////////////////////////////////////////
  225. void Halt_State (void)
  226. {
  227. if (IsHalted) {
  228. return ;
  229. }
  230. //
  231. // Notify the current state that it's "ending"
  232. //
  233. if (Is_Valid_State (CurrState)) {
  234. if (StateTable[CurrState].End != NULL) {
  235. (Object->*(StateTable[CurrState].End)) ();
  236. }
  237. }
  238. IsHalted = true;
  239. return ;
  240. }
  241. ///////////////////////////////////////////////////////////////////
  242. // Resume_State
  243. ///////////////////////////////////////////////////////////////////
  244. void Resume_State (void)
  245. {
  246. if (IsHalted == false) {
  247. return ;
  248. }
  249. //
  250. // Notify the current state that it's starting again
  251. //
  252. if (Is_Valid_State (CurrState)) {
  253. if (StateTable[CurrState].Begin != NULL) {
  254. (Object->*(StateTable[CurrState].Begin)) ();
  255. }
  256. }
  257. IsHalted = false;
  258. return ;
  259. }
  260. ///////////////////////////////////////////////////////////////////
  261. // Get_State
  262. ///////////////////////////////////////////////////////////////////
  263. int Get_State (void)
  264. {
  265. return CurrState;
  266. }
  267. ///////////////////////////////////////////////////////////////////
  268. // Set_State
  269. ///////////////////////////////////////////////////////////////////
  270. void Set_State (int state_index, bool force = false)
  271. {
  272. if (state_index == CurrState && force == false) {
  273. return ;
  274. }
  275. //
  276. // First, check to see if we can switch states
  277. //
  278. if (IsHalted == false && Is_Valid_State (CurrState)) {
  279. if (force == false && StateTable[CurrState].RequestEnd != NULL) {
  280. if ((Object->*(StateTable[CurrState].RequestEnd)) (state_index) == false) {
  281. return ;
  282. }
  283. }
  284. //
  285. // Now, notify the old state that it's ending
  286. //
  287. if (StateTable[CurrState].End != NULL) {
  288. (Object->*(StateTable[CurrState].End)) ();
  289. }
  290. }
  291. if (Is_Valid_State (state_index)) {
  292. //
  293. // Switch to the new state
  294. //
  295. CurrState = state_index;
  296. if (IsHalted == false && StateTable[CurrState].Begin != NULL) {
  297. (Object->*(StateTable[CurrState].Begin)) ();
  298. }
  299. } else {
  300. CurrState = -1;
  301. }
  302. return ;
  303. }
  304. ///////////////////////////////////////////////////////////////////
  305. // Save
  306. ///////////////////////////////////////////////////////////////////
  307. void Save (ChunkSaveClass &csave)
  308. {
  309. csave.Begin_Chunk (CHUNKID_VARIABLES);
  310. WRITE_MICRO_CHUNK (csave, VARID_CURR_STATE, CurrState);
  311. WRITE_MICRO_CHUNK (csave, VARID_IS_HALTED, IsHalted);
  312. csave.End_Chunk ();
  313. return ;
  314. }
  315. ///////////////////////////////////////////////////////////////////
  316. // Load
  317. ///////////////////////////////////////////////////////////////////
  318. void Load (ChunkLoadClass &cload)
  319. {
  320. while (cload.Open_Chunk ())
  321. {
  322. switch (cload.Cur_Chunk_ID ())
  323. {
  324. case CHUNKID_VARIABLES:
  325. Load_Variables (cload);
  326. break;
  327. default:
  328. WWDEBUG_SAY (("Unrecognized StateMachineClass chunkID\n"));
  329. break;
  330. }
  331. cload.Close_Chunk ();
  332. }
  333. return ;
  334. }
  335. ///////////////////////////////////////////////////////////////////
  336. // Load_Variables
  337. ///////////////////////////////////////////////////////////////////
  338. void Load_Variables (ChunkLoadClass &cload)
  339. {
  340. while (cload.Open_Micro_Chunk ()) {
  341. switch (cload.Cur_Micro_Chunk_ID ())
  342. {
  343. READ_MICRO_CHUNK (cload, VARID_CURR_STATE, CurrState);
  344. READ_MICRO_CHUNK (cload, VARID_IS_HALTED, IsHalted);
  345. default:
  346. WWDEBUG_SAY (("Unrecognized StateMachineClass variable chunkID\n"));
  347. break;
  348. }
  349. cload.Close_Micro_Chunk ();
  350. }
  351. return ;
  352. }
  353. protected:
  354. ///////////////////////////////////////////////////////////////////
  355. // Protected methods
  356. ///////////////////////////////////////////////////////////////////
  357. ///////////////////////////////////////////////////////////////////
  358. // Is_Valid_State
  359. ///////////////////////////////////////////////////////////////////
  360. bool Is_Valid_State (int index)
  361. {
  362. return (index >= 0 && index < StateTable.Count ());
  363. }
  364. ///////////////////////////////////////////////////////////////////
  365. // Protected member data
  366. ///////////////////////////////////////////////////////////////////
  367. SimpleDynVecClass<STATE_OBJ> StateTable;
  368. T * Object;
  369. int CurrState;
  370. bool IsHalted;
  371. };
  372. #endif //__STATEMACHINE_H