Revision control
1
/***
2
*
3
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
4
*
5
* This product contains software technology licensed from Id
6
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
7
* All Rights Reserved.
8
*
9
* Use, distribution, and modification of this source code and/or resulting
10
* object code is restricted to non-commercial enhancements to products from
11
* Valve LLC. All other use, distribution, or modification is prohibited
12
* without written permission from Valve LLC.
13
*
14
****/
15
/*
16
17
===== h_cycler.cpp ========================================================
18
19
The Halflife Cycler Monsters
20
21
*/
22
23
#include "extdll.h"
24
#include "util.h"
25
#include "cbase.h"
26
#include "monsters.h"
27
#include "animation.h"
28
#include "weapons.h"
29
#include "player.h"
30
31
32
#define TEMP_FOR_SCREEN_SHOTS
33
#ifdef TEMP_FOR_SCREEN_SHOTS //===================================================
34
35
class CCycler : public CBaseMonster
36
{
37
public:
38
void GenericCyclerSpawn(const char *szModel, Vector vecMin, Vector vecMax);
39
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); }
40
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
41
void Spawn( void );
42
void Think( void );
43
//void Pain( float flDamage );
44
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
45
46
// Don't treat as a live target
47
virtual BOOL IsAlive( void ) { return FALSE; }
48
49
virtual int Save( CSave &save );
50
virtual int Restore( CRestore &restore );
51
static TYPEDESCRIPTION m_SaveData[];
52
53
int m_animate;
54
};
55
56
TYPEDESCRIPTION CCycler::m_SaveData[] =
57
{
58
DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ),
59
};
60
61
IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster );
62
63
64
//
65
// we should get rid of all the other cyclers and replace them with this.
66
//
67
class CGenericCycler : public CCycler
68
{
69
public:
70
void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); }
71
};
72
LINK_ENTITY_TO_CLASS( cycler, CGenericCycler );
73
74
75
76
// Probe droid imported for tech demo compatibility
77
//
78
// PROBE DROID
79
//
80
class CCyclerProbe : public CCycler
81
{
82
public:
83
void Spawn( void );
84
};
85
LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe );
86
void CCyclerProbe :: Spawn( void )
87
{
88
pev->origin = pev->origin + Vector ( 0, 0, 16 );
89
GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16));
90
}
91
92
93
94
// Cycler member functions
95
96
void CCycler :: GenericCyclerSpawn(const char *szModel, Vector vecMin, Vector vecMax)
97
{
98
if (!szModel || !*szModel)
99
{
100
ALERT(at_error, "cycler at %.0f %.0f %0.f missing modelname", pev->origin.x, pev->origin.y, pev->origin.z );
101
REMOVE_ENTITY(ENT(pev));
102
return;
103
}
104
105
pev->classname = MAKE_STRING("cycler");
106
PRECACHE_MODEL( szModel );
107
SET_MODEL(ENT(pev), szModel);
108
109
CCycler::Spawn( );
110
111
UTIL_SetSize(pev, vecMin, vecMax);
112
}
113
114
115
void CCycler :: Spawn( )
116
{
117
InitBoneControllers();
118
pev->solid = SOLID_SLIDEBOX;
119
pev->movetype = MOVETYPE_NONE;
120
pev->takedamage = DAMAGE_YES;
121
pev->effects = 0;
122
pev->health = 80000;// no cycler should die
123
pev->yaw_speed = 5;
124
pev->ideal_yaw = pev->angles.y;
125
ChangeYaw( 360 );
126
127
m_flFrameRate = 75;
128
m_flGroundSpeed = 0;
129
130
pev->nextthink += 1.0;
131
132
ResetSequenceInfo( );
133
134
if (pev->sequence != 0 || pev->frame != 0)
135
{
136
m_animate = 0;
137
pev->framerate = 0;
138
}
139
else
140
{
141
m_animate = 1;
142
}
143
}
144
145
146
147
148
//
149
// cycler think
150
//
151
void CCycler :: Think( void )
152
{
153
pev->nextthink = gpGlobals->time + 0.1;
154
155
if (m_animate)
156
{
157
StudioFrameAdvance ( );
158
}
159
if (m_fSequenceFinished && !m_fSequenceLoops)
160
{
161
// ResetSequenceInfo();
162
// hack to avoid reloading model every frame
163
pev->animtime = gpGlobals->time;
164
pev->framerate = 1.0;
165
m_fSequenceFinished = FALSE;
166
m_flLastEventCheck = gpGlobals->time;
167
pev->frame = 0;
168
if (!m_animate)
169
pev->framerate = 0.0; // FIX: don't reset framerate
170
}
171
}
172
173
//
174
// CyclerUse - starts a rotation trend
175
//
176
void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
177
{
178
m_animate = !m_animate;
179
if (m_animate)
180
pev->framerate = 1.0;
181
else
182
pev->framerate = 0.0;
183
}
184
185
//
186
// CyclerPain , changes sequences when shot
187
//
188
//void CCycler :: Pain( float flDamage )
189
int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
190
{
191
if (m_animate)
192
{
193
pev->sequence++;
194
195
ResetSequenceInfo( );
196
197
if (m_flFrameRate == 0.0)
198
{
199
pev->sequence = 0;
200
ResetSequenceInfo( );
201
}
202
pev->frame = 0;
203
}
204
else
205
{
206
pev->framerate = 1.0;
207
StudioFrameAdvance ( 0.1 );
208
pev->framerate = 0;
209
ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame );
210
}
211
212
return 0;
213
}
214
215
#endif
216
217
218
class CCyclerSprite : public CBaseEntity
219
{
220
public:
221
void Spawn( void );
222
void Think( void );
223
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
224
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_DONT_SAVE | FCAP_IMPULSE_USE); }
225
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
226
void Animate( float frames );
227
228
virtual int Save( CSave &save );
229
virtual int Restore( CRestore &restore );
230
static TYPEDESCRIPTION m_SaveData[];
231
232
inline int ShouldAnimate( void ) { return m_animate && m_maxFrame > 1.0; }
233
int m_animate;
234
float m_lastTime;
235
float m_maxFrame;
236
};
237
238
LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite );
239
240
TYPEDESCRIPTION CCyclerSprite::m_SaveData[] =
241
{
242
DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ),
243
DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ),
244
DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ),
245
};
246
247
IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity );
248
249
250
void CCyclerSprite::Spawn( void )
251
{
252
pev->solid = SOLID_SLIDEBOX;
253
pev->movetype = MOVETYPE_NONE;
254
pev->takedamage = DAMAGE_YES;
255
pev->effects = 0;
256
257
pev->frame = 0;
258
pev->nextthink = gpGlobals->time + 0.1;
259
m_animate = 1;
260
m_lastTime = gpGlobals->time;
261
262
PRECACHE_MODEL( (char *)STRING(pev->model) );
263
SET_MODEL( ENT(pev), STRING(pev->model) );
264
265
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
266
}
267
268
269
void CCyclerSprite::Think( void )
270
{
271
if ( ShouldAnimate() )
272
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
273
274
pev->nextthink = gpGlobals->time + 0.1;
275
m_lastTime = gpGlobals->time;
276
}
277
278
279
void CCyclerSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
280
{
281
m_animate = !m_animate;
282
ALERT( at_console, "Sprite: %s\n", STRING(pev->model) );
283
}
284
285
286
int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
287
{
288
if ( m_maxFrame > 1.0 )
289
{
290
Animate( 1.0 );
291
}
292
return 1;
293
}
294
295
void CCyclerSprite::Animate( float frames )
296
{
297
pev->frame += frames;
298
if ( m_maxFrame > 0 )
299
pev->frame = fmod( pev->frame, m_maxFrame );
300
}
301
302
303
304
305
306
307
308
class CWeaponCycler : public CBasePlayerWeapon
309
{
310
public:
311
void Spawn( void );
312
int iItemSlot( void ) { return 1; }
313
int GetItemInfo(ItemInfo *p) {return 0; }
314
315
void PrimaryAttack( void );
316
void SecondaryAttack( void );
317
BOOL Deploy( void );
318
void Holster( int skiplocal = 0 );
319
int m_iszModel;
320
int m_iModel;
321
};
322
LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler );
323
324
325
void CWeaponCycler::Spawn( )
326
{
327
pev->solid = SOLID_SLIDEBOX;
328
pev->movetype = MOVETYPE_NONE;
329
330
PRECACHE_MODEL( (char *)STRING(pev->model) );
331
SET_MODEL( ENT(pev), STRING(pev->model) );
332
m_iszModel = pev->model;
333
m_iModel = pev->modelindex;
334
335
UTIL_SetOrigin( pev, pev->origin );
336
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));
337
SetTouch( &CWeaponCycler::DefaultTouch );
338
}
339
340
341
342
BOOL CWeaponCycler::Deploy( )
343
{
344
m_pPlayer->pev->viewmodel = m_iszModel;
345
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
346
SendWeaponAnim( 0 );
347
m_iClip = 0;
348
return TRUE;
349
}
350
351
352
void CWeaponCycler::Holster( int skiplocal /* = 0 */ )
353
{
354
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
355
}
356
357
358
void CWeaponCycler::PrimaryAttack()
359
{
360
361
SendWeaponAnim( pev->sequence );
362
363
m_flNextPrimaryAttack = gpGlobals->time + 0.3;
364
}
365
366
367
void CWeaponCycler::SecondaryAttack( void )
368
{
369
float flFrameRate, flGroundSpeed;
370
371
pev->sequence = (pev->sequence + 1) % 8;
372
373
pev->modelindex = m_iModel;
374
void *pmodel = GET_MODEL_PTR( ENT(pev) );
375
GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed );
376
pev->modelindex = 0;
377
378
if (flFrameRate == 0.0)
379
{
380
pev->sequence = 0;
381
}
382
383
SendWeaponAnim( pev->sequence );
384
385
m_flNextSecondaryAttack = gpGlobals->time + 0.3;
386
}
387
388
389
390
// Flaming Wreakage
391
class CWreckage : public CBaseMonster
392
{
393
int Save( CSave &save );
394
int Restore( CRestore &restore );
395
static TYPEDESCRIPTION m_SaveData[];
396
397
void Spawn( void );
398
void Precache( void );
399
void Think( void );
400
401
int m_flStartTime;
402
};
403
TYPEDESCRIPTION CWreckage::m_SaveData[] =
404
{
405
DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ),
406
};
407
IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster );
408
409
410
LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage );
411
412
void CWreckage::Spawn( void )
413
{
414
pev->solid = SOLID_NOT;
415
pev->movetype = MOVETYPE_NONE;
416
pev->takedamage = 0;
417
pev->effects = 0;
418
419
pev->frame = 0;
420
pev->nextthink = gpGlobals->time + 0.1;
421
422
if (pev->model)
423
{
424
PRECACHE_MODEL( (char *)STRING(pev->model) );
425
SET_MODEL( ENT(pev), STRING(pev->model) );
426
}
427
// pev->scale = 5.0;
428
429
m_flStartTime = static_cast<int>(gpGlobals->time);
430
}
431
432
void CWreckage::Precache( )
433
{
434
if ( pev->model )
435
PRECACHE_MODEL( (char *)STRING(pev->model) );
436
}
437
438
void CWreckage::Think( void )
439
{
440
StudioFrameAdvance( );
441
pev->nextthink = gpGlobals->time + 0.2;
442
443
if (pev->dmgtime)
444
{
445
if (pev->dmgtime < gpGlobals->time)
446
{
447
UTIL_Remove( this );
448
return;
449
}
450
else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time)
451
{
452
return;
453
}
454
}
455
456
Vector VecSrc;
457
458
VecSrc.x = RANDOM_FLOAT( pev->absmin.x, pev->absmax.x );
459
VecSrc.y = RANDOM_FLOAT( pev->absmin.y, pev->absmax.y );
460
VecSrc.z = RANDOM_FLOAT( pev->absmin.z, pev->absmax.z );
461
462
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc );
463
WRITE_BYTE( TE_SMOKE );
464
WRITE_COORD( VecSrc.x );
465
WRITE_COORD( VecSrc.y );
466
WRITE_COORD( VecSrc.z );
467
WRITE_SHORT( g_sModelIndexSmoke );
468
WRITE_BYTE( RANDOM_LONG(0,49) + 50 ); // scale * 10
469
WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate
470
MESSAGE_END();
471
}