forked from electronicarts/CnC_Generals_Zero_Hour
-
Notifications
You must be signed in to change notification settings - Fork 184
Expand file tree
/
Copy pathUpdateModule.h
More file actions
365 lines (300 loc) · 14.9 KB
/
UpdateModule.h
File metadata and controls
365 lines (300 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*
** 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
#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 CPP_11(: Int);
//-------------------------------------------------------------------------------------------------
enum UpdateSleepTime CPP_11(: Int)
{
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 CPP_11(: Int)
{
// 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() override { return this; }
// UpdateModuleInterface
virtual UpdateSleepTime update() = 0;
virtual DisabledMaskType getDisabledTypesToProcess() const override
{
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;
virtual const Coord3D* getProjectileLogicVelocity() const { return nullptr; }
};
//-------------------------------------------------------------------------------------------------
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 = nullptr ) = 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() = 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 CPP_11(: Int)
{
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() const = 0; ///< define a "rally point" for units to move towards
virtual Bool useSpawnRallyPoint() 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
};