UpdateModule.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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: UpdateModule.h /////////////////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day, September 2001
  25. // Desc:
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #pragma once
  28. #ifndef __UpdateModule_H_
  29. #define __UpdateModule_H_
  30. #include "Common/Module.h"
  31. #include "Common/GameType.h"
  32. #include "Common/DisabledTypes.h"
  33. #include "GameLogic/Module/BehaviorModule.h"
  34. #define DIRECT_UPDATEMODULE_ACCESS
  35. //-------------------------------------------------------------------------------------------------
  36. /** OBJECT UPDATE MODULE base class */
  37. //-------------------------------------------------------------------------------------------------
  38. //-------------------------------------------------------------------------------------------------
  39. class ProjectileUpdateInterface;
  40. class AIUpdateInterface; ///< @todo Clean up this nasty hack (MSB)
  41. class ExitInterface;
  42. class DockUpdateInterface;
  43. class RailedTransportDockUpdateInterface;
  44. class SpecialPowerUpdateInterface;
  45. class SlavedUpdateInterface;
  46. class SpawnBehavior;
  47. class SlowDeathBehaviorInterface;
  48. class PowerPlantUpdateInterface;
  49. class ProductionUpdateInterface;
  50. class HordeUpdateInterface;
  51. class SpecialPowerTemplate;
  52. class WeaponTemplate;
  53. class DamageInfo;
  54. class ParticleSystemTemplate;
  55. class CommandButton;
  56. class Waypoint;
  57. enum CommandOption;
  58. //-------------------------------------------------------------------------------------------------
  59. enum UpdateSleepTime
  60. {
  61. UPDATE_SLEEP_INVALID = 0,
  62. UPDATE_SLEEP_NONE = 1,
  63. // (we use 0x3fffffff so that we can add offsets and not overflow...
  64. // and also 'cuz we shift the value up by two bits for the phase.
  65. // note that at 30fps, this is ~414 days...
  66. UPDATE_SLEEP_FOREVER = 0x3fffffff
  67. };
  68. #define UPDATE_SLEEP(numFrames) ((UpdateSleepTime)(numFrames))
  69. // this is used to declare in which "phase" sleepy updates are called.
  70. // all phase 0 are called before all phase 1 within a given frame, etc.
  71. // this is really only used to facilitate some internal operations
  72. // in an efficient way while still maintaining order-dependency; you should
  73. // really never specify anything other than PHASE_NORMAL without very
  74. // careful deliberation. If you need to, talk it over with folks first. (srj)
  75. enum SleepyUpdatePhase
  76. {
  77. // reserve 2 bits for phase. this still leaves us 30 bits for frame counter,
  78. // which, at 30fps, will still run for ~414 days without overflowing...
  79. PHASE_INITIAL = 0,
  80. PHASE_PHYSICS = 1,
  81. PHASE_NORMAL = 2,
  82. PHASE_FINAL = 3
  83. };
  84. //-------------------------------------------------------------------------------------------------
  85. class UpdateModuleInterface
  86. {
  87. public:
  88. virtual UpdateSleepTime update() = 0;
  89. virtual DisabledMaskType getDisabledTypesToProcess() const = 0;
  90. #ifdef DIRECT_UPDATEMODULE_ACCESS
  91. // these aren't in the interface; they are in the implementation,
  92. // because making them virtual is simply too much overhead.
  93. // no, really; I have the profiling data to prove it. (srj)
  94. #else
  95. // these are for use ONLY by GameLogic scheduler. do not call otherwise,
  96. // and (generally) don't redefine them either!
  97. virtual UnsignedInt friend_getPriority() const = 0;
  98. virtual UnsignedInt friend_getNextCallFrame() const = 0;
  99. virtual SleepyUpdatePhase friend_getNextCallPhase() const = 0;
  100. virtual void friend_setNextCallFrame(UnsignedInt frame) = 0;
  101. #endif
  102. };
  103. //-------------------------------------------------------------------------------------------------
  104. //-------------------------------------------------------------------------------------------------
  105. //-------------------------------------------------------------------------------------------------
  106. class UpdateModuleData : public BehaviorModuleData
  107. {
  108. public:
  109. static void buildFieldParse(MultiIniFieldParse& p)
  110. {
  111. BehaviorModuleData::buildFieldParse(p);
  112. }
  113. };
  114. //-------------------------------------------------------------------------------------------------
  115. class UpdateModule : public BehaviorModule, public UpdateModuleInterface
  116. {
  117. MEMORY_POOL_GLUE_ABC( UpdateModule )
  118. MAKE_STANDARD_MODULE_MACRO_ABC( UpdateModule )
  119. MAKE_STANDARD_MODULE_DATA_MACRO_ABC(UpdateModule, UpdateModuleData)
  120. private:
  121. // this is an absolute frame, not a frame count.
  122. // actually, it's not a real frame at all, it has phase info in the lower bits...
  123. UnsignedInt m_nextCallFrameAndPhase;
  124. Int m_indexInLogic;
  125. protected:
  126. // yes, protected: modules should only wake themselves up.
  127. void setWakeFrame(Object* obj, UpdateSleepTime wakeDelay);
  128. UpdateSleepTime getWakeFrame() const;
  129. /*
  130. You should pretty much never redefine this; it's really used for
  131. internal purposes by Object. See comment above.
  132. */
  133. virtual SleepyUpdatePhase getUpdatePhase() const
  134. {
  135. return PHASE_NORMAL;
  136. }
  137. UpdateSleepTime frameToSleepTime(UnsignedInt frame1, UnsignedInt frame2 = FOREVER, UnsignedInt frame3 = FOREVER, UnsignedInt frame4 = FOREVER);
  138. public:
  139. UpdateModule( Thing *thing, const ModuleData* moduleData );
  140. // virtual destructor prototype defined by MemoryPoolObject
  141. static Int getInterfaceMask() { return (MODULEINTERFACE_UPDATE); }
  142. // BehaviorModule
  143. virtual UpdateModuleInterface* getUpdate() { return this; }
  144. // UpdateModuleInterface
  145. virtual UpdateSleepTime update() = 0;
  146. DisabledMaskType getDisabledTypesToProcess() const
  147. {
  148. return DISABLEDMASK_NONE;
  149. }
  150. #ifdef DIRECT_UPDATEMODULE_ACCESS
  151. #define UPDATEMODULE_FRIEND_DECLARATOR __forceinline
  152. #else
  153. #define UPDATEMODULE_FRIEND_DECLARATOR virtual
  154. #endif
  155. // for use ONLY by GameLogic scheduler. do not call otherwise.
  156. UPDATEMODULE_FRIEND_DECLARATOR UnsignedInt friend_getPriority() const
  157. {
  158. return m_nextCallFrameAndPhase;
  159. }
  160. UPDATEMODULE_FRIEND_DECLARATOR UnsignedInt friend_getNextCallFrame() const
  161. {
  162. return m_nextCallFrameAndPhase >> 2;
  163. }
  164. UPDATEMODULE_FRIEND_DECLARATOR SleepyUpdatePhase friend_getNextCallPhase() const
  165. {
  166. return (SleepyUpdatePhase)(m_nextCallFrameAndPhase & 3);
  167. }
  168. UPDATEMODULE_FRIEND_DECLARATOR void friend_setNextCallFrame(UnsignedInt frame)
  169. {
  170. // anything greater than "forever" is still "forever"
  171. // (this makes setWakeFrame() comparisons simpler and more efficient)
  172. if (frame > UPDATE_SLEEP_FOREVER)
  173. frame = UPDATE_SLEEP_FOREVER;
  174. m_nextCallFrameAndPhase = (frame << 2) | getUpdatePhase();
  175. }
  176. UPDATEMODULE_FRIEND_DECLARATOR Int friend_getIndexInLogic() const
  177. {
  178. return m_indexInLogic;
  179. }
  180. UPDATEMODULE_FRIEND_DECLARATOR void friend_setIndexInLogic(Int i)
  181. {
  182. m_indexInLogic = i;
  183. }
  184. UPDATEMODULE_FRIEND_DECLARATOR const Object* friend_getObject() const
  185. {
  186. return getObject();
  187. }
  188. };
  189. inline UpdateModule::UpdateModule( Thing *thing, const ModuleData* moduleData ) :
  190. BehaviorModule( thing, moduleData ),
  191. m_indexInLogic(-1),
  192. m_nextCallFrameAndPhase(0)
  193. {
  194. // nothing
  195. }
  196. inline UpdateModule::~UpdateModule()
  197. {
  198. DEBUG_ASSERTCRASH(m_indexInLogic == -1, ("destroying an updatemodule still in the logic list"));
  199. }
  200. //-------------------------------------------------------------------------------------------------
  201. #ifdef DIRECT_UPDATEMODULE_ACCESS
  202. typedef UpdateModule* UpdateModulePtr;
  203. #else
  204. typedef UpdateModuleInterface* UpdateModulePtr;
  205. #endif
  206. //-------------------------------------------------------------------------------------------------
  207. class SlavedUpdateInterface
  208. {
  209. public:
  210. virtual ObjectID getSlaverID() const = 0;
  211. virtual void onEnslave( const Object *slaver ) = 0;
  212. virtual void onSlaverDie( const DamageInfo *info ) = 0;
  213. virtual void onSlaverDamage( const DamageInfo *info ) = 0;
  214. virtual Bool isSelfTasking() const = 0;
  215. };
  216. //-------------------------------------------------------------------------------------------------
  217. class ProjectileUpdateInterface
  218. {
  219. public:
  220. virtual void projectileLaunchAtObjectOrPosition(const Object *victim, const Coord3D* victimPos, const Object *launcher, WeaponSlotType wslot, Int specificBarrelToUse, const WeaponTemplate* detWeap, const ParticleSystemTemplate* exhaustSysOverride) = 0; ///< launch the projectile at the given victim
  221. virtual void projectileFireAtObjectOrPosition( const Object *victim, const Coord3D *victimPos, const WeaponTemplate *detWeap, const ParticleSystemTemplate* exhaustSysOverride ) = 0;
  222. virtual Bool projectileIsArmed() const = 0; ///< return true if the projectile is armed and ready to explode
  223. virtual ObjectID projectileGetLauncherID() const = 0; ///< All projectiles need to keep track of their firer
  224. virtual Bool projectileHandleCollision(Object *other) = 0;
  225. virtual void setFramesTillCountermeasureDiversionOccurs( UnsignedInt frames ) = 0; ///< Number of frames till missile diverts to countermeasures.
  226. virtual void projectileNowJammed() = 0;
  227. };
  228. //-------------------------------------------------------------------------------------------------
  229. class DockUpdateInterface
  230. {
  231. public:
  232. /** Returns true if it is okay for the docker to approach and prepare to dock.
  233. False could mean the queue is full, for example.
  234. */
  235. virtual Bool isClearToApproach( Object const* docker ) const = 0;
  236. /** Give me a Queue point to drive to, and record that that point is taken.
  237. Returning NULL means there are none free
  238. */
  239. virtual Bool reserveApproachPosition( Object* docker, Coord3D *position, Int *index ) = 0;
  240. /** Give me the next Queue point to drive to, and record that that point is taken.
  241. */
  242. virtual Bool advanceApproachPosition( Object* docker, Coord3D *position, Int *index ) = 0;
  243. /** Return true when it is OK for docker to begin entering the dock
  244. The Dock will lift the restriction on one particular docker on its own,
  245. so you must continually ask.
  246. */
  247. virtual Bool isClearToEnter( Object const* docker ) const = 0;
  248. /** Return true when it is OK for docker to request a new Approach position. The dock is in
  249. charge of keeping track of holes in the line, but the docker will remind us of their spot.
  250. */
  251. virtual Bool isClearToAdvance( Object const* docker, Int dockerIndex ) const = 0;
  252. /** Give me the point that is the start of your docking path
  253. Returning NULL means there is none free
  254. All functions take docker as arg so we could have multiple docks on a building.
  255. Docker is not assumed, it is recorded and checked.
  256. */
  257. virtual void getEnterPosition( Object* docker, Coord3D *position ) = 0;
  258. /** Give me the middle point of the dock process where the action() happens */
  259. virtual void getDockPosition( Object* docker, Coord3D *position ) = 0;
  260. /** Give me the point to drive to when I am done */
  261. virtual void getExitPosition( Object* docker, Coord3D *position ) = 0;
  262. virtual void onApproachReached( Object* docker ) = 0; ///< I have reached the Enter Point.
  263. virtual void onEnterReached( Object* docker ) = 0; ///< I have reached the Enter Point.
  264. virtual void onDockReached( Object* docker ) = 0; ///< I have reached the Dock point
  265. virtual void onExitReached( Object* docker ) = 0; ///< I have reached the exit. You are no longer busy
  266. virtual Bool action( Object* docker, Object *drone = NULL ) = 0; ///< Perform your specific action on me. Returning FALSE means there is nothing for you to do so I should leave
  267. virtual void cancelDock( Object* docker ) = 0; ///< Clear me from any reserved points, and if I was the reason you were Busy, you aren't anymore.
  268. virtual Bool isDockOpen( void ) = 0; ///< Is the dock open to accepting dockers
  269. virtual void setDockOpen( Bool open ) = 0; ///< Open/Close the dock
  270. virtual void setDockCrippled( Bool setting ) = 0; ///< Game Logic can set me as inoperative. I get to decide what that means.
  271. virtual Bool isAllowPassthroughType() = 0; ///< Not all docks allow you to path through them in your AIDock machine
  272. virtual Bool isRallyPointAfterDockType() = 0; ///< A minority of docks want to give you a final command to their rally point
  273. };
  274. //-------------------------------------------------------------------------------------------------
  275. enum ExitDoorType
  276. {
  277. DOOR_1 = 0,
  278. DOOR_2 = 1,
  279. DOOR_3 = 2,
  280. DOOR_4 = 3,
  281. DOOR_COUNT_MAX = 4,
  282. DOOR_NONE_AVAILABLE = -1, // need a door, but none currently available
  283. DOOR_NONE_NEEDED = -2 // don't need a door reservation
  284. };
  285. //-------------------------------------------------------------------------------------------------
  286. ///< Different types of modules have an interest in exiting units out of themselves for whatever reason.
  287. class ExitInterface
  288. {
  289. public:
  290. virtual Bool isExitBusy() const = 0; ///< Contain style exiters are getting the ability to space out exits, so ask this before reserveDoor as a kind of no-commitment check.
  291. virtual ExitDoorType reserveDoorForExit( const ThingTemplate* objType, Object *specificObject ) = 0; ///< All types can answer if they are free to exit or not, and you can ask about a specific guy or just exit anything in general
  292. virtual void exitObjectViaDoor( Object *newObj, ExitDoorType exitDoor ) = 0; ///< Here is the object for you to exit to the world in your own special way
  293. virtual void exitObjectByBudding( Object *newObj, Object *budHost ) = 0; ///< puts new spawn on top of an existing one
  294. virtual void unreserveDoorForExit( ExitDoorType exitDoor ) = 0; ///< if you get permission to exit, but then don't/can't call exitObjectViaDoor, you should call this to "give up" your permission
  295. virtual void exitObjectInAHurry( Object *newObj) {}; ///< Special call for objects exiting a tunnel network, does NOT change the ai state. jba.
  296. virtual void setRallyPoint( const Coord3D *pos ) = 0; ///< define a "rally point" for units to move towards
  297. virtual const Coord3D *getRallyPoint( void ) const = 0; ///< define a "rally point" for units to move towards
  298. virtual Bool useSpawnRallyPoint( void ) const { return FALSE; }
  299. virtual Bool getNaturalRallyPoint( Coord3D& rallyPoint, Bool offset = TRUE ) const {rallyPoint.x=rallyPoint.y=rallyPoint.z=0; return false;} ///< get the natural "rally point" for units to move towards
  300. virtual Bool getExitPosition( Coord3D& exitPosition ) const {exitPosition.x=exitPosition.y=exitPosition.z=0; return false;}; ///< access to the "Door" position of the production object
  301. };
  302. #endif