| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: GameCommon.h ////////////////////////////////////////////////////////////
- //-----------------------------------------------------------------------------
- //
- // Westwood Studios Pacific.
- //
- // Confidential Information
- // Copyright (C) 2001 - All Rights Reserved
- //
- //-----------------------------------------------------------------------------
- //
- // Project: RTS3
- //
- // File name: GameCommon.h
- //
- // Created: Steven Johnson, October 2001
- //
- // Desc: This is a catchall header for some basic types and definitions
- // needed by various bits of the GameLogic/GameClient, but that
- // we haven't found a good place for yet. Hopefully this file
- // should go away someday, but for now is a convenient spot.
- //
- //-----------------------------------------------------------------------------
- #pragma once
- #ifndef _GAMECOMMON_H_
- #define _GAMECOMMON_H_
- #define DONT_ALLOW_DEBUG_CHEATS_IN_RELEASE ///< Take of the DONT to get cheats back in to release
- //#define _CAMPEA_DEMO
- // ----------------------------------------------------------------------------------------------
- #include "Lib/BaseType.h"
- // ----------------------------------------------------------------------------------------------
- #if defined(_INTERNAL) || defined(_DEBUG)
- #define DUMP_PERF_STATS
- #else
- #define NO_DUMP_PERF_STATS
- #endif
- // ----------------------------------------------------------------------------------------------
- enum
- {
- LOGICFRAMES_PER_SECOND = 30,
- MSEC_PER_SECOND = 1000
- };
- const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND));
- const Real MSEC_PER_LOGICFRAME_REAL = (((Real)MSEC_PER_SECOND) / ((Real)LOGICFRAMES_PER_SECOND));
- const Real LOGICFRAMES_PER_SECONDS_REAL = (Real)LOGICFRAMES_PER_SECOND;
- const Real SECONDS_PER_LOGICFRAME_REAL = 1.0f / LOGICFRAMES_PER_SECONDS_REAL;
- // ----------------------------------------------------------------------------------------------
- // note that this returns a REAL value, not an int... most callers will want to
- // call ceil() on the result, so that partial frames get converted to full frames!
- inline Real ConvertDurationFromMsecsToFrames(Real msec)
- {
- return (msec * LOGICFRAMES_PER_MSEC_REAL);
- }
- // ----------------------------------------------------------------------------------------------
- inline Real ConvertVelocityInSecsToFrames(Real distPerMsec)
- {
- // this looks wrong, but is the correct conversion factor.
- return (distPerMsec * SECONDS_PER_LOGICFRAME_REAL);
- }
- // ----------------------------------------------------------------------------------------------
- inline Real ConvertAccelerationInSecsToFrames(Real distPerSec2)
- {
- // this looks wrong, but is the correct conversion factor.
- const Real SEC_PER_LOGICFRAME_SQR = (SECONDS_PER_LOGICFRAME_REAL * SECONDS_PER_LOGICFRAME_REAL);
- return (distPerSec2 * SEC_PER_LOGICFRAME_SQR);
- }
- // ----------------------------------------------------------------------------------------------
- inline Real ConvertAngularVelocityInDegreesPerSecToRadsPerFrame(Real degPerSec)
- {
- const Real RADS_PER_DEGREE = PI / 180.0f;
- return (degPerSec * (SECONDS_PER_LOGICFRAME_REAL * RADS_PER_DEGREE));
- }
- // ----------------------------------------------------------------------------------------------
- enum
- {
- MAX_PLAYER_COUNT = 16 ///< max number of Players.
- };
- // ----------------------------------------------------------------------------------------------
- /**
- a bitmask that can uniquely represent each player.
- */
- #if MAX_PLAYER_COUNT <= 16
- typedef UnsignedShort PlayerMaskType;
- const PlayerMaskType PLAYERMASK_ALL = 0xffff;
- const PlayerMaskType PLAYERMASK_NONE = 0x0;
- #else
- #error "this is the wrong size"
- #endif
- // ----------------------------------------------------------------------------------------------
- enum
- {
- MAX_GLOBAL_GENERAL_TYPES = 9, ///< number of playable General Types, not including the boss)
-
- /// The start of the playable global generals playertemplates
- GLOBAL_GENERAL_BEGIN = 5,
-
- /// The end of the playable global generals
- GLOBAL_GENERAL_END = (GLOBAL_GENERAL_BEGIN + MAX_GLOBAL_GENERAL_TYPES - 1)
- };
- //-------------------------------------------------------------------------------------------------
- enum GameDifficulty
- {
- DIFFICULTY_EASY,
- DIFFICULTY_NORMAL,
- DIFFICULTY_HARD,
- DIFFICULTY_COUNT
- };
- //-------------------------------------------------------------------------------------------------
- enum PlayerType
- {
- PLAYER_HUMAN, ///< player is human-controlled
- PLAYER_COMPUTER, ///< player is computer-controlled
- PLAYERTYPE_COUNT
- };
- //-------------------------------------------------------------------------------------------------
- /// A PartitionCell can be one of three states for Shroud
- enum CellShroudStatus
- {
- CELLSHROUD_CLEAR,
- CELLSHROUD_FOGGED,
- CELLSHROUD_SHROUDED,
- CELLSHROUD_COUNT
- };
- //-------------------------------------------------------------------------------------------------
- /// Since an object can take up more than a single PartitionCell, this is a status that applies to the whole Object
- enum ObjectShroudStatus
- {
- OBJECTSHROUD_INVALID, ///< indeterminate state, will recompute
- OBJECTSHROUD_CLEAR, ///< object is not shrouded at all (ie, completely visible)
- OBJECTSHROUD_PARTIAL_CLEAR, ///< object is partly clear (rest is shroud or fog)
- OBJECTSHROUD_FOGGED, ///< object is completely fogged
- OBJECTSHROUD_SHROUDED, ///< object is completely shrouded
- OBJECTSHROUD_INVALID_BUT_PREVIOUS_VALID, ///< indeterminate state, will recompute, BUT previous status is valid, don't reset (used for save/load)
- OBJECTSHROUD_COUNT
- };
- //-------------------------------------------------------------------------------------------------
- enum GuardMode
- {
- GUARDMODE_NORMAL,
- GUARDMODE_GUARD_WITHOUT_PURSUIT, // no pursuit out of guard area
- GUARDMODE_GUARD_FLYING_UNITS_ONLY // ignore nonflyers
- };
- // ---------------------------------------------------
- enum
- {
- NEVER = 0,
- FOREVER = 0x3fffffff // (we use 0x3fffffff so that we can add offsets and not overflow...
- // at 30fps we're still pretty safe!)
- };
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- /// Veterancy level define needed by several files that don't need the full Experience code.
- // NOTE NOTE NOTE: Keep TheVeterencyNames in sync with these.
- enum VeterancyLevel
- {
- LEVEL_REGULAR = 0,
- LEVEL_VETERAN,
- LEVEL_ELITE,
- LEVEL_HEROIC,
- LEVEL_COUNT,
- LEVEL_INVALID,
- LEVEL_FIRST = LEVEL_REGULAR,
- LEVEL_LAST = LEVEL_HEROIC
- };
- // TheVeterancyNames is defined in GameCommon.cpp
- extern const char *TheVeterancyNames[];
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- enum CommandSourceType
- {
- CMD_FROM_PLAYER = 0,
- CMD_FROM_SCRIPT,
- CMD_FROM_AI,
- 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.
- CMD_DEFAULT_SWITCH_WEAPON, // Special case: A weapon that can be chosen -- this is the default case (machine gun vs flashbang).
- }; ///< the source of a command
- //-------------------------------------------------------------------------------------------------
- enum AbleToAttackType
- {
- _ATTACK_FORCED = 0x01,
- _ATTACK_CONTINUED = 0x02,
- _ATTACK_TUNNELNETWORK_GUARD = 0x04,
- /**
- can we attack if this is a new target?
- */
- ATTACK_NEW_TARGET = (0),
- /**
- can we attack if this is a new target, via force-fire?
- (The only current difference between this and ATTACK_NEW_TARGET is that disguised units
- are force-attackable even when stealthed.)
- */
- ATTACK_NEW_TARGET_FORCED= (_ATTACK_FORCED),
- /**
- can we attack if this is continuation of an existing attack?
- (The only current difference between this and ATTACK_NEW_TARGET is you are allowed to follow
- immobile shrouded units into the fog)
- */
- ATTACK_CONTINUED_TARGET = (_ATTACK_CONTINUED),
- /**
- can we attack if this is continuation of an existing attack?
- (The only current difference between this and ATTACK_NEW_TARGET is you are allowed to follow
- immobile shrouded units into the fog)
- */
- ATTACK_CONTINUED_TARGET_FORCED = (_ATTACK_FORCED | _ATTACK_CONTINUED),
- /**
- Special case that bypasses some of the checks for units guarding from within tunnel networks!
- For example, a unit inside couldn't normally see outside and would fail.
- */
- ATTACK_TUNNEL_NETWORK_GUARD = (_ATTACK_TUNNELNETWORK_GUARD)
-
- };
- //-------------------------------------------------------------------------------------------------
- inline Bool isForcedAttack(AbleToAttackType t)
- {
- return (((Int)t) & _ATTACK_FORCED) != 0;
- }
- //-------------------------------------------------------------------------------------------------
- inline Bool isContinuedAttack(AbleToAttackType t)
- {
- return (((Int)t) & _ATTACK_CONTINUED) != 0;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- typedef UnsignedInt VeterancyLevelFlags;
- const VeterancyLevelFlags VETERANCY_LEVEL_FLAGS_ALL = 0xffffffff;
- const VeterancyLevelFlags VETERANCY_LEVEL_FLAGS_NONE = 0x00000000;
- inline Bool getVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
- {
- return (flags & (1UL << (dt - 1))) != 0;
- }
- inline VeterancyLevelFlags setVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
- {
- return (flags | (1UL << (dt - 1)));
- }
- inline VeterancyLevelFlags clearVeterancyLevelFlag(VeterancyLevelFlags flags, VeterancyLevel dt)
- {
- return (flags & ~(1UL << (dt - 1)));
- }
- // ----------------------------------------------------------------------------------------------
- #define BOGUSPTR(p) ((((unsigned int)(p)) & 1) != 0)
- // ----------------------------------------------------------------------------------------------
- #define MAKE_DLINK_HEAD(OBJCLASS, LISTNAME) \
- public: \
- inline DLINK_ITERATOR<OBJCLASS> iterate_##LISTNAME() const \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
- return DLINK_ITERATOR<OBJCLASS>(m_dlinkhead_##LISTNAME.m_head, OBJCLASS::dlink_next_##LISTNAME); \
- } \
- inline OBJCLASS *getFirstItemIn_##LISTNAME() const \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
- return m_dlinkhead_##LISTNAME.m_head; \
- } \
- inline Bool isInList_##LISTNAME(OBJCLASS* o) const \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
- return o->dlink_isInList_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
- } \
- inline void prependTo_##LISTNAME(OBJCLASS* o) \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
- if (!isInList_##LISTNAME(o)) \
- o->dlink_prependTo_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
- } \
- inline void removeFrom_##LISTNAME(OBJCLASS* o) \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr")); \
- if (isInList_##LISTNAME(o)) \
- o->dlink_removeFrom_##LISTNAME(&m_dlinkhead_##LISTNAME.m_head); \
- } \
- typedef void (*RemoveAllProc_##LISTNAME)(OBJCLASS* o); \
- inline void removeAll_##LISTNAME(RemoveAllProc_##LISTNAME p = NULL) \
- { \
- while (m_dlinkhead_##LISTNAME.m_head) \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(m_dlinkhead_##LISTNAME.m_head), ("bogus head ptr"));\
- OBJCLASS *tmp = m_dlinkhead_##LISTNAME.m_head; \
- removeFrom_##LISTNAME(tmp); \
- if (p) (*p)(tmp); \
- } \
- } \
- inline void reverse_##LISTNAME() \
- { \
- OBJCLASS* cur = m_dlinkhead_##LISTNAME.m_head; \
- OBJCLASS* prev = NULL; \
- while (cur) \
- { \
- OBJCLASS* originalNext = cur->dlink_next_##LISTNAME(); \
- cur->dlink_swapLinks_##LISTNAME(); \
- prev = cur; \
- cur = originalNext; \
- } \
- m_dlinkhead_##LISTNAME.m_head = prev; \
- } \
- private: \
- /* a trick: init head to zero */ \
- struct DLINKHEAD_##LISTNAME \
- { \
- public: \
- OBJCLASS* m_head; \
- inline DLINKHEAD_##LISTNAME() : \
- m_head(0) { } \
- inline ~DLINKHEAD_##LISTNAME() \
- { DEBUG_ASSERTCRASH(!m_head,("destroying dlinkhead still in a list " #LISTNAME)); } \
- }; \
- DLINKHEAD_##LISTNAME m_dlinkhead_##LISTNAME;
- // ----------------------------------------------------------------------------------------------
- #define MAKE_DLINK(OBJCLASS, LISTNAME) \
- public: \
- OBJCLASS* dlink_prev_##LISTNAME() const { return m_dlink_##LISTNAME.m_prev; } \
- OBJCLASS* dlink_next_##LISTNAME() const { return m_dlink_##LISTNAME.m_next; } \
- void dlink_swapLinks_##LISTNAME() \
- { \
- OBJCLASS* originalNext = m_dlink_##LISTNAME.m_next; \
- m_dlink_##LISTNAME.m_next = m_dlink_##LISTNAME.m_prev; \
- m_dlink_##LISTNAME.m_prev = originalNext; \
- } \
- Bool dlink_isInList_##LISTNAME(OBJCLASS* const* pListHead) const \
- { \
- DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
- return *pListHead == this || m_dlink_##LISTNAME.m_prev || m_dlink_##LISTNAME.m_next; \
- } \
- void dlink_prependTo_##LISTNAME(OBJCLASS** pListHead) \
- { \
- DEBUG_ASSERTCRASH(!dlink_isInList_##LISTNAME(pListHead), ("already in list " #LISTNAME)); \
- DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
- m_dlink_##LISTNAME.m_next = *pListHead; \
- if (*pListHead) \
- (*pListHead)->m_dlink_##LISTNAME.m_prev = this; \
- *pListHead = this; \
- DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
- } \
- void dlink_removeFrom_##LISTNAME(OBJCLASS** pListHead) \
- { \
- DEBUG_ASSERTCRASH(dlink_isInList_##LISTNAME(pListHead), ("not in list" #LISTNAME)); \
- DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
- if (m_dlink_##LISTNAME.m_next) \
- m_dlink_##LISTNAME.m_next->m_dlink_##LISTNAME.m_prev = m_dlink_##LISTNAME.m_prev; \
- if (m_dlink_##LISTNAME.m_prev) \
- m_dlink_##LISTNAME.m_prev->m_dlink_##LISTNAME.m_next = m_dlink_##LISTNAME.m_next; \
- else \
- *pListHead = m_dlink_##LISTNAME.m_next; \
- m_dlink_##LISTNAME.m_prev = 0; \
- m_dlink_##LISTNAME.m_next = 0; \
- DEBUG_ASSERTCRASH(!BOGUSPTR(*pListHead) && !BOGUSPTR(m_dlink_##LISTNAME.m_next) && !BOGUSPTR(m_dlink_##LISTNAME.m_prev), ("bogus ptrs")); \
- } \
- private: \
- /* a trick: init links to zero */ \
- struct DLINK_##LISTNAME \
- { \
- public: \
- OBJCLASS* m_prev; \
- OBJCLASS* m_next; \
- inline DLINK_##LISTNAME() : \
- m_prev(0), m_next(0) { } \
- inline ~DLINK_##LISTNAME() \
- { DEBUG_ASSERTCRASH(!m_prev && !m_next,("destroying dlink still in a list " #LISTNAME)); } \
- }; \
- DLINK_##LISTNAME m_dlink_##LISTNAME;
- // ------------------------------------------------------------------------
- // this is the weird C++ syntax for "call pointer-to-member-function"... see C++ FAQ LITE for details.
- #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
- // ------------------------------------------------------------------------
- template<class OBJCLASS>
- class DLINK_ITERATOR
- {
- public:
- // this is the weird C++ syntax for "pointer-to-member-function"
- typedef OBJCLASS* (OBJCLASS::*GetNextFunc)() const;
- private:
- OBJCLASS* m_cur;
- GetNextFunc m_getNextFunc; // this is the weird C++ syntax for "pointer-to-member-function"
- public:
- DLINK_ITERATOR(OBJCLASS* cur, GetNextFunc getNextFunc) : m_cur(cur), m_getNextFunc(getNextFunc)
- {
- }
-
- void advance()
- {
- if (m_cur)
- m_cur = callMemberFunction(*m_cur, m_getNextFunc)();
- }
-
- Bool done() const
- {
- return m_cur == NULL;
- }
- OBJCLASS* cur() const
- {
- return m_cur;
- }
- };
- // ------------------------------------------------------------------------
- enum WhichTurretType
- {
- TURRET_INVALID = -1,
- TURRET_MAIN = 0,
- TURRET_ALT,
- MAX_TURRETS
- };
- // ------------------------------------------------------------------------
- // this normalizes an angle to the range -PI...PI.
- extern Real normalizeAngle(Real angle);
- // ------------------------------------------------------------------------
- // this returns the difference between a1 and a2, normalized.
- inline Real stdAngleDiff(Real a1, Real a2)
- {
- return normalizeAngle(a1 - a2);
- }
- // ------------------------------------------------------------------------
- // NOTE NOTE NOTE: Keep TheRelationShipNames in sync with this enum
- enum Relationship
- {
- ENEMIES = 0,
- NEUTRAL,
- ALLIES
- };
- // TheRelationShipNames is defined in Common/GameCommon.cpp
- extern const char *TheRelationshipNames[];
- #endif // _GAMECOMMON_H_
|