GameCommon.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: GameCommon.h ////////////////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: GameCommon.h
  36. //
  37. // Created: Steven Johnson, October 2001
  38. //
  39. // Desc: This is a catchall header for some basic types and definitions
  40. // needed by various bits of the GameLogic/GameClient, but that
  41. // we haven't found a good place for yet. Hopefully this file
  42. // should go away someday, but for now is a convenient spot.
  43. //
  44. //-----------------------------------------------------------------------------
  45. #pragma once
  46. #ifndef _GAMECOMMON_H_
  47. #define _GAMECOMMON_H_
  48. #define DONT_ALLOW_DEBUG_CHEATS_IN_RELEASE ///< Take of the DONT to get cheats back in to release
  49. //#define _CAMPEA_DEMO
  50. // ----------------------------------------------------------------------------------------------
  51. #include "Lib/BaseType.h"
  52. // ----------------------------------------------------------------------------------------------
  53. #if defined(_INTERNAL) || defined(_DEBUG)
  54. #define DUMP_PERF_STATS
  55. #else
  56. #define NO_DUMP_PERF_STATS
  57. #endif
  58. // ----------------------------------------------------------------------------------------------
  59. enum
  60. {
  61. LOGICFRAMES_PER_SECOND = 30,
  62. MSEC_PER_SECOND = 1000
  63. };
  64. const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND));
  65. const Real MSEC_PER_LOGICFRAME_REAL = (((Real)MSEC_PER_SECOND) / ((Real)LOGICFRAMES_PER_SECOND));
  66. const Real LOGICFRAMES_PER_SECONDS_REAL = (Real)LOGICFRAMES_PER_SECOND;
  67. const Real SECONDS_PER_LOGICFRAME_REAL = 1.0f / LOGICFRAMES_PER_SECONDS_REAL;
  68. // ----------------------------------------------------------------------------------------------
  69. // note that this returns a REAL value, not an int... most callers will want to
  70. // call ceil() on the result, so that partial frames get converted to full frames!
  71. inline Real ConvertDurationFromMsecsToFrames(Real msec)
  72. {
  73. return (msec * LOGICFRAMES_PER_MSEC_REAL);
  74. }
  75. // ----------------------------------------------------------------------------------------------
  76. inline Real ConvertVelocityInSecsToFrames(Real distPerMsec)
  77. {
  78. // this looks wrong, but is the correct conversion factor.
  79. return (distPerMsec * SECONDS_PER_LOGICFRAME_REAL);
  80. }
  81. // ----------------------------------------------------------------------------------------------
  82. inline Real ConvertAccelerationInSecsToFrames(Real distPerSec2)
  83. {
  84. // this looks wrong, but is the correct conversion factor.
  85. const Real SEC_PER_LOGICFRAME_SQR = (SECONDS_PER_LOGICFRAME_REAL * SECONDS_PER_LOGICFRAME_REAL);
  86. return (distPerSec2 * SEC_PER_LOGICFRAME_SQR);
  87. }
  88. // ----------------------------------------------------------------------------------------------
  89. inline Real ConvertAngularVelocityInDegreesPerSecToRadsPerFrame(Real degPerSec)
  90. {
  91. const Real RADS_PER_DEGREE = PI / 180.0f;
  92. return (degPerSec * (SECONDS_PER_LOGICFRAME_REAL * RADS_PER_DEGREE));
  93. }
  94. // ----------------------------------------------------------------------------------------------
  95. enum
  96. {
  97. MAX_PLAYER_COUNT = 16 ///< max number of Players.
  98. };
  99. // ----------------------------------------------------------------------------------------------
  100. /**
  101. a bitmask that can uniquely represent each player.
  102. */
  103. #if MAX_PLAYER_COUNT <= 16
  104. typedef UnsignedShort PlayerMaskType;
  105. const PlayerMaskType PLAYERMASK_ALL = 0xffff;
  106. const PlayerMaskType PLAYERMASK_NONE = 0x0;
  107. #else
  108. #error "this is the wrong size"
  109. #endif
  110. // ----------------------------------------------------------------------------------------------
  111. enum
  112. {
  113. MAX_GLOBAL_GENERAL_TYPES = 9, ///< number of playable General Types, not including the boss)
  114. /// The start of the playable global generals playertemplates
  115. GLOBAL_GENERAL_BEGIN = 5,
  116. /// The end of the playable global generals
  117. GLOBAL_GENERAL_END = (GLOBAL_GENERAL_BEGIN + MAX_GLOBAL_GENERAL_TYPES - 1)
  118. };
  119. //-------------------------------------------------------------------------------------------------
  120. enum GameDifficulty
  121. {
  122. DIFFICULTY_EASY,
  123. DIFFICULTY_NORMAL,
  124. DIFFICULTY_HARD,
  125. DIFFICULTY_COUNT
  126. };
  127. //-------------------------------------------------------------------------------------------------
  128. enum PlayerType
  129. {
  130. PLAYER_HUMAN, ///< player is human-controlled
  131. PLAYER_COMPUTER, ///< player is computer-controlled
  132. PLAYERTYPE_COUNT
  133. };
  134. //-------------------------------------------------------------------------------------------------
  135. /// A PartitionCell can be one of three states for Shroud
  136. enum CellShroudStatus
  137. {
  138. CELLSHROUD_CLEAR,
  139. CELLSHROUD_FOGGED,
  140. CELLSHROUD_SHROUDED,
  141. CELLSHROUD_COUNT
  142. };
  143. //-------------------------------------------------------------------------------------------------
  144. /// Since an object can take up more than a single PartitionCell, this is a status that applies to the whole Object
  145. enum ObjectShroudStatus
  146. {
  147. OBJECTSHROUD_INVALID, ///< indeterminate state, will recompute
  148. OBJECTSHROUD_CLEAR, ///< object is not shrouded at all (ie, completely visible)
  149. OBJECTSHROUD_PARTIAL_CLEAR, ///< object is partly clear (rest is shroud or fog)
  150. OBJECTSHROUD_FOGGED, ///< object is completely fogged
  151. OBJECTSHROUD_SHROUDED, ///< object is completely shrouded
  152. OBJECTSHROUD_INVALID_BUT_PREVIOUS_VALID, ///< indeterminate state, will recompute, BUT previous status is valid, don't reset (used for save/load)
  153. OBJECTSHROUD_COUNT
  154. };
  155. //-------------------------------------------------------------------------------------------------
  156. enum GuardMode
  157. {
  158. GUARDMODE_NORMAL,
  159. GUARDMODE_GUARD_WITHOUT_PURSUIT, // no pursuit out of guard area
  160. GUARDMODE_GUARD_FLYING_UNITS_ONLY // ignore nonflyers
  161. };
  162. // ---------------------------------------------------
  163. enum
  164. {
  165. NEVER = 0,
  166. FOREVER = 0x3fffffff // (we use 0x3fffffff so that we can add offsets and not overflow...
  167. // at 30fps we're still pretty safe!)
  168. };
  169. //-------------------------------------------------------------------------------------------------
  170. //-------------------------------------------------------------------------------------------------
  171. //-------------------------------------------------------------------------------------------------
  172. /// Veterancy level define needed by several files that don't need the full Experience code.
  173. // NOTE NOTE NOTE: Keep TheVeterencyNames in sync with these.
  174. enum VeterancyLevel
  175. {
  176. LEVEL_REGULAR = 0,
  177. LEVEL_VETERAN,
  178. LEVEL_ELITE,
  179. LEVEL_HEROIC,
  180. LEVEL_COUNT,
  181. LEVEL_INVALID,
  182. LEVEL_FIRST = LEVEL_REGULAR,
  183. LEVEL_LAST = LEVEL_HEROIC
  184. };
  185. // TheVeterancyNames is defined in GameCommon.cpp
  186. extern const char *TheVeterancyNames[];
  187. //-------------------------------------------------------------------------------------------------
  188. //-------------------------------------------------------------------------------------------------
  189. enum CommandSourceType
  190. {
  191. CMD_FROM_PLAYER = 0,
  192. CMD_FROM_SCRIPT,
  193. CMD_FROM_AI,
  194. CMD_FROM_DOZER, // Special rare command when the dozer originates a command to attack a mine. Mines are not ai-attackable, and it seems deceitful for the dozer to generate a player or script command. jba.
  195. CMD_DEFAULT_SWITCH_WEAPON, // Special case: A weapon that can be chosen -- this is the default case (machine gun vs flashbang).
  196. }; ///< the source of a command
  197. //-------------------------------------------------------------------------------------------------
  198. enum AbleToAttackType
  199. {
  200. _ATTACK_FORCED = 0x01,
  201. _ATTACK_CONTINUED = 0x02,
  202. _ATTACK_TUNNELNETWORK_GUARD = 0x04,
  203. /**
  204. can we attack if this is a new target?
  205. */
  206. ATTACK_NEW_TARGET = (0),
  207. /**
  208. can we attack if this is a new target, via force-fire?
  209. (The only current difference between this and ATTACK_NEW_TARGET is that disguised units
  210. are force-attackable even when stealthed.)
  211. */
  212. ATTACK_NEW_TARGET_FORCED= (_ATTACK_FORCED),
  213. /**
  214. can we attack if this is continuation of an existing attack?
  215. (The only current difference between this and ATTACK_NEW_TARGET is you are allowed to follow
  216. immobile shrouded units into the fog)
  217. */
  218. ATTACK_CONTINUED_TARGET = (_ATTACK_CONTINUED),
  219. /**
  220. can we attack if this is continuation of an existing attack?
  221. (The only current difference between this and ATTACK_NEW_TARGET is you are allowed to follow
  222. immobile shrouded units into the fog)
  223. */
  224. ATTACK_CONTINUED_TARGET_FORCED = (_ATTACK_FORCED | _ATTACK_CONTINUED),
  225. /**
  226. Special case that bypasses some of the checks for units guarding from within tunnel networks!
  227. For example, a unit inside couldn't normally see outside and would fail.
  228. */
  229. ATTACK_TUNNEL_NETWORK_GUARD = (_ATTACK_TUNNELNETWORK_GUARD)
  230. };
  231. //-------------------------------------------------------------------------------------------------
  232. inline Bool isForcedAttack(AbleToAttackType t)
  233. {
  234. return (((Int)t) & _ATTACK_FORCED) != 0;
  235. }
  236. //-------------------------------------------------------------------------------------------------
  237. inline Bool isContinuedAttack(AbleToAttackType t)
  238. {
  239. return (((Int)t) & _ATTACK_CONTINUED) != 0;
  240. }
  241. //-------------------------------------------------------------------------------------------------
  242. //-------------------------------------------------------------------------------------------------
  243. typedef UnsignedInt VeterancyLevelFlags;
  244. const VeterancyLevelFlags VETERANCY_LEVEL_FLAGS_ALL = 0xffffffff;
  245. const VeterancyLevelFlags VETERANCY_LEVEL_FLAGS_NONE = 0x00000000;
  246. inline Bool getVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
  247. {
  248. return (flags & (1UL << (dt - 1))) != 0;
  249. }
  250. inline VeterancyLevelFlags setVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
  251. {
  252. return (flags | (1UL << (dt - 1)));
  253. }
  254. inline VeterancyLevelFlags clearVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
  255. {
  256. return (flags & ~(1UL << (dt - 1)));
  257. }
  258. // ----------------------------------------------------------------------------------------------
  259. #define BOGUSPTR(p) ((((unsigned int)(p)) & 1) != 0)
  260. // ----------------------------------------------------------------------------------------------
  261. #define MAKE_DLINK_HEAD(OBJCLASS, LISTNAME) \
  262. public: \
  263. inline DLINK_ITERATOR<OBJCLASS> iterate_##LISTNAME() const \
  264. { \
  265. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
  266. return DLINK_ITERATOR<OBJCLASS>(m_dlinkhead_##LISTNAME.m_head, OBJCLASS::dlink_next_##LISTNAME); \
  267. } \
  268. inline OBJCLASS *getFirstItemIn_##LISTNAME() const \
  269. { \
  270. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
  271. return m_dlinkhead_##LISTNAME.m_head; \
  272. } \
  273. inline Bool isInList_##LISTNAME(OBJCLASS* o) const \
  274. { \
  275. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
  276. return o->dlink_isInList_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
  277. } \
  278. inline void prependTo_##LISTNAME(OBJCLASS* o) \
  279. { \
  280. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
  281. if (!isInList_##LISTNAME(o)) \
  282. o->dlink_prependTo_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
  283. } \
  284. inline void removeFrom_##LISTNAME(OBJCLASS* o) \
  285. { \
  286. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
  287. if (isInList_##LISTNAME(o)) \
  288. o->dlink_removeFrom_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
  289. } \
  290. typedef void (*RemoveAllProc_##LISTNAME)(OBJCLASS* o); \
  291. inline void removeAll_##LISTNAME(RemoveAllProc_##LISTNAME p = NULL) \
  292. { \
  293. while (m_dlinkhead_##LISTNAME.m_head) \
  294. { \
  295. DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr"));\
  296. OBJCLASS *tmp = m_dlinkhead_##LISTNAME.m_head; \
  297. removeFrom_##LISTNAME(tmp); \
  298. if (p) (*p)(tmp); \
  299. } \
  300. } \
  301. inline void reverse_##LISTNAME() \
  302. { \
  303. OBJCLASS* cur = m_dlinkhead_##LISTNAME.m_head; \
  304. OBJCLASS* prev = NULL; \
  305. while (cur) \
  306. { \
  307. OBJCLASS* originalNext = cur->dlink_next_##LISTNAME(); \
  308. cur->dlink_swapLinks_##LISTNAME(); \
  309. prev = cur; \
  310. cur = originalNext; \
  311. } \
  312. m_dlinkhead_##LISTNAME.m_head = prev; \
  313. } \
  314. private: \
  315. /* a trick: init head to zero */ \
  316. struct DLINKHEAD_##LISTNAME \
  317. { \
  318. public: \
  319. OBJCLASS* m_head; \
  320. inline DLINKHEAD_##LISTNAME() : \
  321. m_head(0) { } \
  322. inline ~DLINKHEAD_##LISTNAME() \
  323. { DEBUG_ASSERTCRASH(!m_head,("destroying dlinkhead still in a list " #LISTNAME)); } \
  324. }; \
  325. DLINKHEAD_##LISTNAME m_dlinkhead_##LISTNAME;
  326. // ----------------------------------------------------------------------------------------------
  327. #define MAKE_DLINK(OBJCLASS, LISTNAME) \
  328. public: \
  329. OBJCLASS* dlink_prev_##LISTNAME() const { return m_dlink_##LISTNAME.m_prev; } \
  330. OBJCLASS* dlink_next_##LISTNAME() const { return m_dlink_##LISTNAME.m_next; } \
  331. void dlink_swapLinks_##LISTNAME() \
  332. { \
  333. OBJCLASS* originalNext = m_dlink_##LISTNAME.m_next; \
  334. m_dlink_##LISTNAME.m_next = m_dlink_##LISTNAME.m_prev; \
  335. m_dlink_##LISTNAME.m_prev = originalNext; \
  336. } \
  337. Bool dlink_isInList_##LISTNAME(OBJCLASS* const* pListHead) const \
  338. { \
  339. DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
  340. return *pListHead == this || m_dlink_##LISTNAME.m_prev || m_dlink_##LISTNAME.m_next; \
  341. } \
  342. void dlink_prependTo_##LISTNAME(OBJCLASS** pListHead) \
  343. { \
  344. DEBUG_ASSERTCRASH(!dlink_isInList_##LISTNAME(pListHead), ("already in list " #LISTNAME)); \
  345. DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
  346. m_dlink_##LISTNAME.m_next = *pListHead; \
  347. if (*pListHead) \
  348. (*pListHead)->m_dlink_##LISTNAME.m_prev = this; \
  349. *pListHead = this; \
  350. DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
  351. } \
  352. void dlink_removeFrom_##LISTNAME(OBJCLASS** pListHead) \
  353. { \
  354. DEBUG_ASSERTCRASH(dlink_isInList_##LISTNAME(pListHead), ("not in list" #LISTNAME)); \
  355. DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
  356. if (m_dlink_##LISTNAME.m_next) \
  357. m_dlink_##LISTNAME.m_next->m_dlink_##LISTNAME.m_prev = m_dlink_##LISTNAME.m_prev; \
  358. if (m_dlink_##LISTNAME.m_prev) \
  359. m_dlink_##LISTNAME.m_prev->m_dlink_##LISTNAME.m_next = m_dlink_##LISTNAME.m_next; \
  360. else \
  361. *pListHead = m_dlink_##LISTNAME.m_next; \
  362. m_dlink_##LISTNAME.m_prev = 0; \
  363. m_dlink_##LISTNAME.m_next = 0; \
  364. DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
  365. } \
  366. private: \
  367. /* a trick: init links to zero */ \
  368. struct DLINK_##LISTNAME \
  369. { \
  370. public: \
  371. OBJCLASS* m_prev; \
  372. OBJCLASS* m_next; \
  373. inline DLINK_##LISTNAME() : \
  374. m_prev(0), m_next(0) { } \
  375. inline ~DLINK_##LISTNAME() \
  376. { DEBUG_ASSERTCRASH(!m_prev && !m_next,("destroying dlink still in a list " #LISTNAME)); } \
  377. }; \
  378. DLINK_##LISTNAME m_dlink_##LISTNAME;
  379. // ------------------------------------------------------------------------
  380. // this is the weird C++ syntax for "call pointer-to-member-function"... see C++ FAQ LITE for details.
  381. #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
  382. // ------------------------------------------------------------------------
  383. template<class OBJCLASS>
  384. class DLINK_ITERATOR
  385. {
  386. public:
  387. // this is the weird C++ syntax for "pointer-to-member-function"
  388. typedef OBJCLASS* (OBJCLASS::*GetNextFunc)() const;
  389. private:
  390. OBJCLASS* m_cur;
  391. GetNextFunc m_getNextFunc; // this is the weird C++ syntax for "pointer-to-member-function"
  392. public:
  393. DLINK_ITERATOR(OBJCLASS* cur, GetNextFunc getNextFunc) : m_cur(cur), m_getNextFunc(getNextFunc)
  394. {
  395. }
  396. void advance()
  397. {
  398. if (m_cur)
  399. m_cur = callMemberFunction(*m_cur, m_getNextFunc)();
  400. }
  401. Bool done() const
  402. {
  403. return m_cur == NULL;
  404. }
  405. OBJCLASS* cur() const
  406. {
  407. return m_cur;
  408. }
  409. };
  410. // ------------------------------------------------------------------------
  411. enum WhichTurretType
  412. {
  413. TURRET_INVALID = -1,
  414. TURRET_MAIN = 0,
  415. TURRET_ALT,
  416. MAX_TURRETS
  417. };
  418. // ------------------------------------------------------------------------
  419. // this normalizes an angle to the range -PI...PI.
  420. extern Real normalizeAngle(Real angle);
  421. // ------------------------------------------------------------------------
  422. // this returns the difference between a1 and a2, normalized.
  423. inline Real stdAngleDiff(Real a1, Real a2)
  424. {
  425. return normalizeAngle(a1 - a2);
  426. }
  427. // ------------------------------------------------------------------------
  428. // NOTE NOTE NOTE: Keep TheRelationShipNames in sync with this enum
  429. enum Relationship
  430. {
  431. ENEMIES = 0,
  432. NEUTRAL,
  433. ALLIES
  434. };
  435. // TheRelationShipNames is defined in Common/GameCommon.cpp
  436. extern const char *TheRelationshipNames[];
  437. #endif // _GAMECOMMON_H_