| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /*
- ** 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: UpdateModule.h /////////////////////////////////////////////////////////////////////////////////
- // Author: Colin Day, September 2001
- // Desc:
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma once
- #ifndef __UpdateModule_H_
- #define __UpdateModule_H_
- #include "Common/Module.h"
- #include "Common/GameType.h"
- #include "Common/DisabledTypes.h"
- #include "GameLogic/Module/BehaviorModule.h"
- #define DIRECT_UPDATEMODULE_ACCESS
- //-------------------------------------------------------------------------------------------------
- /** OBJECT UPDATE MODULE base class */
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- class ProjectileUpdateInterface;
- class AIUpdateInterface; ///< @todo Clean up this nasty hack (MSB)
- class ExitInterface;
- class DockUpdateInterface;
- class RailedTransportDockUpdateInterface;
- class SpecialPowerUpdateInterface;
- class SlavedUpdateInterface;
- class SpawnBehavior;
- class SlowDeathBehaviorInterface;
- class PowerPlantUpdateInterface;
- class ProductionUpdateInterface;
- class HordeUpdateInterface;
- class SpecialPowerTemplate;
- class WeaponTemplate;
- class DamageInfo;
- class ParticleSystemTemplate;
- class CommandButton;
- class Waypoint;
- enum CommandOption;
- //-------------------------------------------------------------------------------------------------
- enum UpdateSleepTime
- {
- UPDATE_SLEEP_INVALID = 0,
- UPDATE_SLEEP_NONE = 1,
- // (we use 0x3fffffff so that we can add offsets and not overflow...
- // and also 'cuz we shift the value up by two bits for the phase.
- // note that at 30fps, this is ~414 days...
- UPDATE_SLEEP_FOREVER = 0x3fffffff
- };
- #define UPDATE_SLEEP(numFrames) ((UpdateSleepTime)(numFrames))
- // this is used to declare in which "phase" sleepy updates are called.
- // all phase 0 are called before all phase 1 within a given frame, etc.
- // this is really only used to facilitate some internal operations
- // in an efficient way while still maintaining order-dependency; you should
- // really never specify anything other than PHASE_NORMAL without very
- // careful deliberation. If you need to, talk it over with folks first. (srj)
- enum SleepyUpdatePhase
- {
- // reserve 2 bits for phase. this still leaves us 30 bits for frame counter,
- // which, at 30fps, will still run for ~414 days without overflowing...
- PHASE_INITIAL = 0,
- PHASE_PHYSICS = 1,
- PHASE_NORMAL = 2,
- PHASE_FINAL = 3
- };
-
- //-------------------------------------------------------------------------------------------------
- class UpdateModuleInterface
- {
- public:
- virtual UpdateSleepTime update() = 0;
- virtual DisabledMaskType getDisabledTypesToProcess() const = 0;
- #ifdef DIRECT_UPDATEMODULE_ACCESS
- // these aren't in the interface; they are in the implementation,
- // because making them virtual is simply too much overhead.
- // no, really; I have the profiling data to prove it. (srj)
- #else
- // these are for use ONLY by GameLogic scheduler. do not call otherwise,
- // and (generally) don't redefine them either!
- virtual UnsignedInt friend_getPriority() const = 0;
- virtual UnsignedInt friend_getNextCallFrame() const = 0;
- virtual SleepyUpdatePhase friend_getNextCallPhase() const = 0;
- virtual void friend_setNextCallFrame(UnsignedInt frame) = 0;
- #endif
- };
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- class UpdateModuleData : public BehaviorModuleData
- {
- public:
- static void buildFieldParse(MultiIniFieldParse& p)
- {
- BehaviorModuleData::buildFieldParse(p);
- }
- };
- //-------------------------------------------------------------------------------------------------
- class UpdateModule : public BehaviorModule, public UpdateModuleInterface
- {
- MEMORY_POOL_GLUE_ABC( UpdateModule )
- MAKE_STANDARD_MODULE_MACRO_ABC( UpdateModule )
- MAKE_STANDARD_MODULE_DATA_MACRO_ABC(UpdateModule, UpdateModuleData)
- private:
- // this is an absolute frame, not a frame count.
- // actually, it's not a real frame at all, it has phase info in the lower bits...
- UnsignedInt m_nextCallFrameAndPhase;
- Int m_indexInLogic;
- protected:
- // yes, protected: modules should only wake themselves up.
- void setWakeFrame(Object* obj, UpdateSleepTime wakeDelay);
- UpdateSleepTime getWakeFrame() const;
- /*
- You should pretty much never redefine this; it's really used for
- internal purposes by Object. See comment above.
- */
- virtual SleepyUpdatePhase getUpdatePhase() const
- {
- return PHASE_NORMAL;
- }
- UpdateSleepTime frameToSleepTime(UnsignedInt frame1, UnsignedInt frame2 = FOREVER, UnsignedInt frame3 = FOREVER, UnsignedInt frame4 = FOREVER);
- public:
- UpdateModule( Thing *thing, const ModuleData* moduleData );
- // virtual destructor prototype defined by MemoryPoolObject
- static Int getInterfaceMask() { return (MODULEINTERFACE_UPDATE); }
- // BehaviorModule
- virtual UpdateModuleInterface* getUpdate() { return this; }
- // UpdateModuleInterface
- virtual UpdateSleepTime update() = 0;
- DisabledMaskType getDisabledTypesToProcess() const
- {
- return DISABLEDMASK_NONE;
- }
- #ifdef DIRECT_UPDATEMODULE_ACCESS
- #define UPDATEMODULE_FRIEND_DECLARATOR __forceinline
- #else
- #define UPDATEMODULE_FRIEND_DECLARATOR virtual
- #endif
- // for use ONLY by GameLogic scheduler. do not call otherwise.
- UPDATEMODULE_FRIEND_DECLARATOR UnsignedInt friend_getPriority() const
- {
- return m_nextCallFrameAndPhase;
- }
- UPDATEMODULE_FRIEND_DECLARATOR UnsignedInt friend_getNextCallFrame() const
- {
- return m_nextCallFrameAndPhase >> 2;
- }
- UPDATEMODULE_FRIEND_DECLARATOR SleepyUpdatePhase friend_getNextCallPhase() const
- {
- return (SleepyUpdatePhase)(m_nextCallFrameAndPhase & 3);
- }
- UPDATEMODULE_FRIEND_DECLARATOR void friend_setNextCallFrame(UnsignedInt frame)
- {
- // anything greater than "forever" is still "forever"
- // (this makes setWakeFrame() comparisons simpler and more efficient)
- if (frame > UPDATE_SLEEP_FOREVER)
- frame = UPDATE_SLEEP_FOREVER;
- m_nextCallFrameAndPhase = (frame << 2) | getUpdatePhase();
- }
- UPDATEMODULE_FRIEND_DECLARATOR Int friend_getIndexInLogic() const
- {
- return m_indexInLogic;
- }
- UPDATEMODULE_FRIEND_DECLARATOR void friend_setIndexInLogic(Int i)
- {
- m_indexInLogic = i;
- }
- UPDATEMODULE_FRIEND_DECLARATOR const Object* friend_getObject() const
- {
- return getObject();
- }
- };
- inline UpdateModule::UpdateModule( Thing *thing, const ModuleData* moduleData ) :
- BehaviorModule( thing, moduleData ),
- m_indexInLogic(-1),
- m_nextCallFrameAndPhase(0)
- {
- // nothing
- }
- inline UpdateModule::~UpdateModule()
- {
- DEBUG_ASSERTCRASH(m_indexInLogic == -1, ("destroying an updatemodule still in the logic list"));
- }
- //-------------------------------------------------------------------------------------------------
- #ifdef DIRECT_UPDATEMODULE_ACCESS
- typedef UpdateModule* UpdateModulePtr;
- #else
- typedef UpdateModuleInterface* UpdateModulePtr;
- #endif
- //-------------------------------------------------------------------------------------------------
- class SlavedUpdateInterface
- {
- public:
- virtual ObjectID getSlaverID() const = 0;
- virtual void onEnslave( const Object *slaver ) = 0;
- virtual void onSlaverDie( const DamageInfo *info ) = 0;
- virtual void onSlaverDamage( const DamageInfo *info ) = 0;
- virtual Bool isSelfTasking() const = 0;
- };
- //-------------------------------------------------------------------------------------------------
- class ProjectileUpdateInterface
- {
- public:
- 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
- virtual void projectileFireAtObjectOrPosition( const Object *victim, const Coord3D *victimPos, const WeaponTemplate *detWeap, const ParticleSystemTemplate* exhaustSysOverride ) = 0;
- virtual Bool projectileIsArmed() const = 0; ///< return true if the projectile is armed and ready to explode
- virtual ObjectID projectileGetLauncherID() const = 0; ///< All projectiles need to keep track of their firer
- virtual Bool projectileHandleCollision(Object *other) = 0;
- virtual void setFramesTillCountermeasureDiversionOccurs( UnsignedInt frames ) = 0; ///< Number of frames till missile diverts to countermeasures.
- virtual void projectileNowJammed() = 0;
- };
- //-------------------------------------------------------------------------------------------------
- class DockUpdateInterface
- {
- public:
- /** Returns true if it is okay for the docker to approach and prepare to dock.
- False could mean the queue is full, for example.
- */
- virtual Bool isClearToApproach( Object const* docker ) const = 0;
- /** Give me a Queue point to drive to, and record that that point is taken.
- Returning NULL means there are none free
- */
- virtual Bool reserveApproachPosition( Object* docker, Coord3D *position, Int *index ) = 0;
- /** Give me the next Queue point to drive to, and record that that point is taken.
- */
- virtual Bool advanceApproachPosition( Object* docker, Coord3D *position, Int *index ) = 0;
- /** Return true when it is OK for docker to begin entering the dock
- The Dock will lift the restriction on one particular docker on its own,
- so you must continually ask.
- */
- virtual Bool isClearToEnter( Object const* docker ) const = 0;
- /** Return true when it is OK for docker to request a new Approach position. The dock is in
- charge of keeping track of holes in the line, but the docker will remind us of their spot.
- */
- virtual Bool isClearToAdvance( Object const* docker, Int dockerIndex ) const = 0;
- /** Give me the point that is the start of your docking path
- Returning NULL means there is none free
- All functions take docker as arg so we could have multiple docks on a building.
- Docker is not assumed, it is recorded and checked.
- */
- virtual void getEnterPosition( Object* docker, Coord3D *position ) = 0;
- /** Give me the middle point of the dock process where the action() happens */
- virtual void getDockPosition( Object* docker, Coord3D *position ) = 0;
- /** Give me the point to drive to when I am done */
- virtual void getExitPosition( Object* docker, Coord3D *position ) = 0;
- virtual void onApproachReached( Object* docker ) = 0; ///< I have reached the Enter Point.
- virtual void onEnterReached( Object* docker ) = 0; ///< I have reached the Enter Point.
- virtual void onDockReached( Object* docker ) = 0; ///< I have reached the Dock point
- virtual void onExitReached( Object* docker ) = 0; ///< I have reached the exit. You are no longer busy
- 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
- 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.
- virtual Bool isDockOpen( void ) = 0; ///< Is the dock open to accepting dockers
- virtual void setDockOpen( Bool open ) = 0; ///< Open/Close the dock
-
- virtual void setDockCrippled( Bool setting ) = 0; ///< Game Logic can set me as inoperative. I get to decide what that means.
- virtual Bool isAllowPassthroughType() = 0; ///< Not all docks allow you to path through them in your AIDock machine
-
- virtual Bool isRallyPointAfterDockType() = 0; ///< A minority of docks want to give you a final command to their rally point
- };
- //-------------------------------------------------------------------------------------------------
- enum ExitDoorType
- {
- DOOR_1 = 0,
- DOOR_2 = 1,
- DOOR_3 = 2,
- DOOR_4 = 3,
- DOOR_COUNT_MAX = 4,
- DOOR_NONE_AVAILABLE = -1, // need a door, but none currently available
- DOOR_NONE_NEEDED = -2 // don't need a door reservation
- };
- //-------------------------------------------------------------------------------------------------
- ///< Different types of modules have an interest in exiting units out of themselves for whatever reason.
- class ExitInterface
- {
- public:
- 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.
- 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
- virtual void exitObjectViaDoor( Object *newObj, ExitDoorType exitDoor ) = 0; ///< Here is the object for you to exit to the world in your own special way
- virtual void exitObjectByBudding( Object *newObj, Object *budHost ) = 0; ///< puts new spawn on top of an existing one
- 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
-
- virtual void exitObjectInAHurry( Object *newObj) {}; ///< Special call for objects exiting a tunnel network, does NOT change the ai state. jba.
- virtual void setRallyPoint( const Coord3D *pos ) = 0; ///< define a "rally point" for units to move towards
- virtual const Coord3D *getRallyPoint( void ) const = 0; ///< define a "rally point" for units to move towards
- virtual Bool useSpawnRallyPoint( void ) const { return FALSE; }
- 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
- virtual Bool getExitPosition( Coord3D& exitPosition ) const {exitPosition.x=exitPosition.y=exitPosition.z=0; return false;}; ///< access to the "Door" position of the production object
- };
- #endif
|