root/src/game/g_missile.c @ 78:dcde131dddae

Revision 78:dcde131dddae, 22.5 kB (checked in by mdoison, 3 years ago)

add goon.patch (tjw 1.2)

  • goon+ is now at s2
  • improve goons capacities
  • pounce give always a knockback
  • improve pounce effect
  • give splash damage to pounceball
Line 
1/*
2===========================================================================
3Copyright (C) 1999-2005 Id Software, Inc.
4Copyright (C) 2000-2006 Tim Angus
5
6This file is part of Tremulous.
7
8Tremulous is free software; you can redistribute it
9and/or modify it under the terms of the GNU General Public License as
10published by the Free Software Foundation; either version 2 of the License,
11or (at your option) any later version.
12
13Tremulous is distributed in the hope that it will be
14useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with Tremulous; if not, write to the Free Software
20Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21===========================================================================
22*/
23
24#include "g_local.h"
25
26#define MISSILE_PRESTEP_TIME  50
27
28/*
29================
30G_BounceMissile
31
32================
33*/
34void G_BounceMissile( gentity_t *ent, trace_t *trace )
35{
36  vec3_t  velocity;
37  float dot;
38  int   hitTime;
39
40  // reflect the velocity on the trace plane
41  hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
42  BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
43  dot = DotProduct( velocity, trace->plane.normal );
44  VectorMA( velocity, -2 * dot, trace->plane.normal, ent->s.pos.trDelta );
45
46  if( ent->s.eFlags & EF_BOUNCE_HALF )
47  {
48    VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
49    // check for stop
50    if( trace->plane.normal[ 2 ] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 )
51    {
52      G_SetOrigin( ent, trace->endpos );
53      return;
54    }
55  }
56
57  VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin );
58  VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
59  ent->s.pos.trTime = level.time;
60}
61
62
63/*
64================
65G_ExplodeMissile
66
67Explode a missile without an impact
68================
69*/
70void G_ExplodeMissile( gentity_t *ent )
71{
72  vec3_t    dir;
73  vec3_t    origin;
74
75  BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
76  SnapVector( origin );
77  G_SetOrigin( ent, origin );
78
79  // we don't have a valid direction, so just point straight up
80  dir[ 0 ] = dir[ 1 ] = 0;
81  dir[ 2 ] = 1;
82
83  ent->s.eType = ET_GENERAL;
84
85  //TA: tired... can't be fucked... hack
86  if( ent->s.weapon != WP_LOCKBLOB_LAUNCHER &&
87      ent->s.weapon != WP_FLAMER )
88    G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
89
90  ent->freeAfterEvent = qtrue;
91
92  // splash damage
93  if( ent->splashDamage )
94    G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage,
95                    ent->splashRadius, ent, ent->splashMethodOfDeath );
96
97  trap_LinkEntity( ent );
98}
99
100void AHive_ReturnToHive( gentity_t *self );
101
102/*
103================
104G_MissileImpact
105
106================
107*/
108void G_MissileImpact( gentity_t *ent, trace_t *trace )
109{
110  gentity_t   *other, *attacker;
111  qboolean    returnAfterDamage = qfalse;
112  vec3_t      dir;
113
114  other = &g_entities[ trace->entityNum ];
115  attacker = &g_entities[ ent->r.ownerNum ];
116
117  // check for bounce
118  if( !other->takedamage &&
119      ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) )
120  {
121    G_BounceMissile( ent, trace );
122
123    //only play a sound if requested
124    if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
125      G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
126
127    return;
128  }
129
130  if( !strcmp( ent->classname, "grenade" ) )
131  {
132    //grenade doesn't explode on impact
133    G_BounceMissile( ent, trace );
134
135    //only play a sound if requested
136    if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
137      G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
138
139    return;
140  }
141  else if( !strcmp( ent->classname, "lockblob" ) )
142  {
143    if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
144    {
145      other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED;
146      other->client->lastLockTime = level.time;
147      AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
148      other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
149    }
150  }
151  else if( !strcmp( ent->classname, "slowblob" ) )
152  {
153    if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
154    {
155      other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED;
156      other->client->lastSlowTime = level.time;
157      AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
158      other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
159    }
160  }
161  else if( !strcmp( ent->classname, "hive" ) )
162  {
163    if( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE )
164    {
165      if( !ent->parent )
166        G_Printf( S_COLOR_YELLOW "WARNING: hive entity has no parent in G_MissileImpact\n" );
167      else
168        ent->parent->active = qfalse;
169
170      G_FreeEntity( ent );
171      return;
172    }
173    else
174    {
175      //prevent collision with the client when returning
176      ent->r.ownerNum = other->s.number;
177
178      ent->think = AHive_ReturnToHive;
179      ent->nextthink = level.time + FRAMETIME;
180
181      //only damage humans
182      if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
183        returnAfterDamage = qtrue;
184      else
185        return;
186    }
187  }
188
189  // impact damage
190  if( other->takedamage )
191  {
192    // FIXME: wrong damage direction?
193    if( ent->damage )
194    {
195      vec3_t  velocity;
196
197      BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
198      if( VectorLength( velocity ) == 0 )
199        velocity[ 2 ] = 1;  // stepped on a grenade
200
201      G_Damage( other, ent, attacker, velocity, ent->s.origin, ent->damage,
202        0, ent->methodOfDeath );
203    }
204  }
205
206  if( returnAfterDamage )
207    return;
208
209  // is it cheaper in bandwidth to just remove this ent and create a new
210  // one, rather than changing the missile into the explosion?
211
212  if( other->takedamage && other->client )
213  {
214    G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
215    ent->s.otherEntityNum = other->s.number;
216  }
217  else if( trace->surfaceFlags & SURF_METALSTEPS )
218    G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
219  else
220    G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
221
222  ent->freeAfterEvent = qtrue;
223
224  // change over to a normal entity right at the point of impact
225  ent->s.eType = ET_GENERAL;
226
227  SnapVectorTowards( trace->endpos, ent->s.pos.trBase );  // save net bandwidth
228
229  G_SetOrigin( ent, trace->endpos );
230
231  // splash damage (doesn't apply to person directly hit)
232  if( ent->splashDamage )
233    G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
234                    other, ent->splashMethodOfDeath );
235
236  trap_LinkEntity( ent );
237}
238
239
240/*
241================
242G_RunMissile
243
244================
245*/
246void G_RunMissile( gentity_t *ent )
247{
248  vec3_t    origin;
249  trace_t   tr;
250  int     passent;
251
252  // get current position
253  BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
254
255  // ignore interactions with the missile owner
256  passent = ent->r.ownerNum;
257
258  // trace a line from the previous position to the current position
259  trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
260
261  if( tr.startsolid || tr.allsolid )
262  {
263    // make sure the tr.entityNum is set to the entity we're stuck in
264    trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
265    tr.fraction = 0;
266  }
267  else
268    VectorCopy( tr.endpos, ent->r.currentOrigin );
269
270  ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
271  trap_LinkEntity( ent );
272  ent->r.contents = 0; //...encoding bbox information
273
274  if( tr.fraction != 1 )
275  {
276    // never explode or bounce on sky
277    if( tr.surfaceFlags & SURF_NOIMPACT )
278    {
279      // If grapple, reset owner
280      if( ent->parent && ent->parent->client && ent->parent->client->hook == ent )
281        ent->parent->client->hook = NULL;
282
283      G_FreeEntity( ent );
284      return;
285    }
286
287    G_MissileImpact( ent, &tr );
288    if( ent->s.eType != ET_MISSILE )
289      return;   // exploded
290  }
291
292  // check think function after bouncing
293  G_RunThink( ent );
294}
295
296
297//=============================================================================
298
299/*
300=================
301fire_flamer
302
303=================
304*/
305gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t dir )
306{
307  gentity_t *bolt;
308  vec3_t    pvel;
309
310  VectorNormalize (dir);
311
312  bolt = G_Spawn();
313  bolt->classname = "flame";
314  bolt->nextthink = level.time + FLAMER_LIFETIME;
315  bolt->think = G_ExplodeMissile;
316  bolt->s.eType = ET_MISSILE;
317  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
318  bolt->s.weapon = WP_FLAMER;
319  bolt->s.generic1 = self->s.generic1; //weaponMode
320  bolt->r.ownerNum = self->s.number;
321  bolt->parent = self;
322  bolt->damage = FLAMER_DMG;
323  bolt->splashDamage = FLAMER_DMG;
324  bolt->splashRadius = FLAMER_RADIUS;
325  bolt->methodOfDeath = MOD_FLAMER;
326  bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH;
327  bolt->clipmask = MASK_SHOT;
328  bolt->target_ent = NULL;
329  bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -15.0f;
330  bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 15.0f;
331
332  bolt->s.pos.trType = TR_LINEAR;
333  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
334  VectorCopy( start, bolt->s.pos.trBase );
335  VectorScale( self->client->ps.velocity, FLAMER_LAG, pvel );
336  VectorMA( pvel, FLAMER_SPEED, dir, bolt->s.pos.trDelta );
337  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
338
339  VectorCopy( start, bolt->r.currentOrigin );
340
341  return bolt;
342}
343
344//=============================================================================
345
346/*
347=================
348fire_blaster
349
350=================
351*/
352gentity_t *fire_blaster( gentity_t *self, vec3_t start, vec3_t dir )
353{
354  gentity_t *bolt;
355
356  VectorNormalize (dir);
357
358  bolt = G_Spawn();
359  bolt->classname = "blaster";
360  bolt->nextthink = level.time + 10000;
361  bolt->think = G_ExplodeMissile;
362  bolt->s.eType = ET_MISSILE;
363  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
364  bolt->s.weapon = WP_BLASTER;
365  bolt->s.generic1 = self->s.generic1; //weaponMode
366  bolt->r.ownerNum = self->s.number;
367  bolt->parent = self;
368  bolt->damage = BLASTER_DMG;
369  bolt->splashDamage = 0;
370  bolt->splashRadius = 0;
371  bolt->methodOfDeath = MOD_BLASTER;
372  bolt->splashMethodOfDeath = MOD_BLASTER;
373  bolt->clipmask = MASK_SHOT;
374  bolt->target_ent = NULL;
375
376  bolt->s.pos.trType = TR_LINEAR;
377  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
378  VectorCopy( start, bolt->s.pos.trBase );
379  VectorScale( dir, BLASTER_SPEED, bolt->s.pos.trDelta );
380  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
381
382  VectorCopy( start, bolt->r.currentOrigin );
383
384  return bolt;
385}
386
387//=============================================================================
388
389/*
390=================
391fire_pulseRifle
392
393=================
394*/
395gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir )
396{
397  gentity_t *bolt;
398
399  VectorNormalize (dir);
400
401  bolt = G_Spawn();
402  bolt->classname = "pulse";
403  bolt->nextthink = level.time + 10000;
404  bolt->think = G_ExplodeMissile;
405  bolt->s.eType = ET_MISSILE;
406  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
407  bolt->s.weapon = WP_PULSE_RIFLE;
408  bolt->s.generic1 = self->s.generic1; //weaponMode
409  bolt->r.ownerNum = self->s.number;
410  bolt->parent = self;
411  bolt->damage = PRIFLE_DMG;
412  bolt->splashDamage = 0;
413  bolt->splashRadius = 0;
414  bolt->methodOfDeath = MOD_PRIFLE;
415  bolt->splashMethodOfDeath = MOD_PRIFLE;
416  bolt->clipmask = MASK_SHOT;
417  bolt->target_ent = NULL;
418
419  bolt->s.pos.trType = TR_LINEAR;
420  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
421  VectorCopy( start, bolt->s.pos.trBase );
422  VectorScale( dir, PRIFLE_SPEED, bolt->s.pos.trDelta );
423  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
424
425  VectorCopy( start, bolt->r.currentOrigin );
426
427  return bolt;
428}
429
430//=============================================================================
431
432/*
433=================
434fire_luciferCannon
435
436=================
437*/
438gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius )
439{
440  gentity_t *bolt;
441  int localDamage = (int)( ceil( ( (float)damage /
442                                   (float)LCANNON_TOTAL_CHARGE ) * (float)LCANNON_DAMAGE ) );
443
444  VectorNormalize( dir );
445
446  bolt = G_Spawn( );
447  bolt->classname = "lcannon";
448
449  if( damage == LCANNON_TOTAL_CHARGE )
450    bolt->nextthink = level.time;
451  else
452    bolt->nextthink = level.time + 10000;
453
454  bolt->think = G_ExplodeMissile;
455  bolt->s.eType = ET_MISSILE;
456  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
457  bolt->s.weapon = WP_LUCIFER_CANNON;
458  bolt->s.generic1 = self->s.generic1; //weaponMode
459  bolt->r.ownerNum = self->s.number;
460  bolt->parent = self;
461  bolt->damage = localDamage;
462  bolt->splashDamage = localDamage / 2;
463  bolt->splashRadius = radius;
464  bolt->methodOfDeath = MOD_LCANNON;
465  bolt->splashMethodOfDeath = MOD_LCANNON_SPLASH;
466  bolt->clipmask = MASK_SHOT;
467  bolt->target_ent = NULL;
468
469  bolt->s.pos.trType = TR_LINEAR;
470  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
471  VectorCopy( start, bolt->s.pos.trBase );
472  VectorScale( dir, LCANNON_SPEED, bolt->s.pos.trDelta );
473  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
474
475  VectorCopy( start, bolt->r.currentOrigin );
476
477  return bolt;
478}
479
480/*
481=================
482launch_grenade
483
484=================
485*/
486gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir )
487{
488  gentity_t *bolt;
489
490  VectorNormalize( dir );
491
492  bolt = G_Spawn( );
493  bolt->classname = "grenade";
494  bolt->nextthink = level.time + 5000;
495  bolt->think = G_ExplodeMissile;
496  bolt->s.eType = ET_MISSILE;
497  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
498  bolt->s.weapon = WP_GRENADE;
499  bolt->s.eFlags = EF_BOUNCE_HALF;
500  bolt->s.generic1 = WPM_PRIMARY; //weaponMode
501  bolt->r.ownerNum = self->s.number;
502  bolt->parent = self;
503  bolt->damage = GRENADE_DAMAGE;
504  bolt->splashDamage = GRENADE_DAMAGE;
505  bolt->splashRadius = GRENADE_RANGE;
506  bolt->methodOfDeath = MOD_GRENADE;
507  bolt->splashMethodOfDeath = MOD_GRENADE;
508  bolt->clipmask = MASK_SHOT;
509  bolt->target_ent = NULL;
510  bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -3.0f;
511  bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 3.0f;
512  bolt->s.time = level.time;
513
514  bolt->s.pos.trType = TR_GRAVITY;
515  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
516  VectorCopy( start, bolt->s.pos.trBase );
517  VectorScale( dir, GRENADE_SPEED, bolt->s.pos.trDelta );
518  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
519
520  VectorCopy( start, bolt->r.currentOrigin );
521
522  return bolt;
523}
524//=============================================================================
525
526/*
527================
528AHive_ReturnToHive
529
530Adjust the trajectory to point towards the hive
531================
532*/
533void AHive_ReturnToHive( gentity_t *self )
534{
535  vec3_t  dir;
536  trace_t tr;
537
538  if( !self->parent )
539  {
540    G_Printf( S_COLOR_YELLOW "WARNING: AHive_ReturnToHive called with no self->parent\n" );
541    return;
542  }
543
544  trap_UnlinkEntity( self->parent );
545  trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
546              self->parent->r.currentOrigin, self->r.ownerNum, self->clipmask );
547  trap_LinkEntity( self->parent );
548
549  if( tr.fraction < 1.0f )
550  {
551    //if can't see hive then disperse
552    VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
553    self->s.pos.trType = TR_STATIONARY;
554    self->s.pos.trTime = level.time;
555
556    self->think = G_ExplodeMissile;
557    self->nextthink = level.time + 2000;
558    self->parent->active = qfalse; //allow the parent to start again
559  }
560  else
561  {
562    VectorSubtract( self->parent->r.currentOrigin, self->r.currentOrigin, dir );
563    VectorNormalize( dir );
564
565    //change direction towards the hive
566    VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
567    SnapVector( self->s.pos.trDelta );      // save net bandwidth
568    VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
569    self->s.pos.trTime = level.time;
570
571    self->think = G_ExplodeMissile;
572    self->nextthink = level.time + 15000;
573  }
574}
575
576/*
577================
578AHive_SearchAndDestroy
579
580Adjust the trajectory to point towards the target
581================
582*/
583void AHive_SearchAndDestroy( gentity_t *self )
584{
585  vec3_t dir;
586  trace_t tr;
587
588  trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs,
589              self->target_ent->r.currentOrigin, self->r.ownerNum, self->clipmask );
590
591  //if there is no LOS or the parent hive is too far away or the target is dead, return
592  if( tr.entityNum == ENTITYNUM_WORLD ||
593      Distance( self->r.currentOrigin, self->parent->r.currentOrigin ) > ( HIVE_RANGE * 5 ) ||
594      self->target_ent->health <= 0 )
595  {
596    self->r.ownerNum = ENTITYNUM_WORLD;
597
598    self->think = AHive_ReturnToHive;
599    self->nextthink = level.time + FRAMETIME;
600  }
601  else
602  {
603    VectorSubtract( self->target_ent->r.currentOrigin, self->r.currentOrigin, dir );
604    VectorNormalize( dir );
605
606    //change direction towards the player
607    VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta );
608    SnapVector( self->s.pos.trDelta );      // save net bandwidth
609    VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
610    self->s.pos.trTime = level.time;
611
612    self->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
613  }
614}
615
616/*
617=================
618fire_hive
619=================
620*/
621gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir )
622{
623  gentity_t *bolt;
624
625  VectorNormalize ( dir );
626
627  bolt = G_Spawn( );
628  bolt->classname = "hive";
629  bolt->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
630  bolt->think = AHive_SearchAndDestroy;
631  bolt->s.eType = ET_MISSILE;
632  bolt->s.eFlags |= EF_BOUNCE|EF_NO_BOUNCE_SOUND;
633  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
634  bolt->s.weapon = WP_HIVE;
635  bolt->s.generic1 = WPM_PRIMARY; //weaponMode
636  bolt->r.ownerNum = self->s.number;
637  bolt->parent = self;
638  bolt->damage = HIVE_DMG;
639  bolt->splashDamage = 0;
640  bolt->splashRadius = 0;
641  bolt->methodOfDeath = MOD_SWARM;
642  bolt->clipmask = MASK_SHOT;
643  bolt->target_ent = self->target_ent;
644
645  bolt->s.pos.trType = TR_LINEAR;
646  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
647  VectorCopy( start, bolt->s.pos.trBase );
648  VectorScale( dir, HIVE_SPEED, bolt->s.pos.trDelta );
649  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
650  VectorCopy( start, bolt->r.currentOrigin );
651
652  return bolt;
653}
654
655//=============================================================================
656
657/*
658=================
659fire_lockblob
660=================
661*/
662gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir )
663{
664  gentity_t *bolt;
665
666  VectorNormalize ( dir );
667
668  bolt = G_Spawn( );
669  bolt->classname = "lockblob";
670  bolt->nextthink = level.time + 15000;
671  bolt->think = G_ExplodeMissile;
672  bolt->s.eType = ET_MISSILE;
673  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
674  bolt->s.weapon = WP_LOCKBLOB_LAUNCHER;
675  bolt->s.generic1 = WPM_PRIMARY; //weaponMode
676  bolt->r.ownerNum = self->s.number;
677  bolt->parent = self;
678  bolt->damage = 0;
679  bolt->splashDamage = 0;
680  bolt->splashRadius = 0;
681  bolt->methodOfDeath = MOD_UNKNOWN; //doesn't do damage so will never kill
682  bolt->clipmask = MASK_SHOT;
683  bolt->target_ent = NULL;
684
685  bolt->s.pos.trType = TR_LINEAR;
686  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
687  VectorCopy( start, bolt->s.pos.trBase );
688  VectorScale( dir, 500, bolt->s.pos.trDelta );
689  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
690  VectorCopy( start, bolt->r.currentOrigin );
691
692  return bolt;
693}
694
695/*
696=================
697fire_slowBlob
698=================
699*/
700gentity_t *fire_slowBlob( gentity_t *self, vec3_t start, vec3_t dir )
701{
702  gentity_t *bolt;
703
704  VectorNormalize ( dir );
705
706  bolt = G_Spawn( );
707  bolt->classname = "slowblob";
708  bolt->nextthink = level.time + 15000;
709  bolt->think = G_ExplodeMissile;
710  bolt->s.eType = ET_MISSILE;
711  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
712  bolt->s.weapon = WP_ABUILD2;
713  bolt->s.generic1 = self->s.generic1; //weaponMode
714  bolt->r.ownerNum = self->s.number;
715  bolt->parent = self;
716  bolt->damage = ABUILDER_BLOB_DMG;
717  bolt->splashDamage = 0;
718  bolt->splashRadius = 0;
719  bolt->methodOfDeath = MOD_SLOWBLOB;
720  bolt->splashMethodOfDeath = MOD_SLOWBLOB;
721  bolt->clipmask = MASK_SHOT;
722  bolt->target_ent = NULL;
723
724  bolt->s.pos.trType = TR_GRAVITY;
725  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
726  VectorCopy( start, bolt->s.pos.trBase );
727  VectorScale( dir, ABUILDER_BLOB_SPEED, bolt->s.pos.trDelta );
728  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
729  VectorCopy( start, bolt->r.currentOrigin );
730
731  return bolt;
732}
733
734/*
735=================
736fire_paraLockBlob
737=================
738*/
739gentity_t *fire_paraLockBlob( gentity_t *self, vec3_t start, vec3_t dir )
740{
741  gentity_t *bolt;
742
743  VectorNormalize ( dir );
744
745  bolt = G_Spawn( );
746  bolt->classname = "lockblob";
747  bolt->nextthink = level.time + 15000;
748  bolt->think = G_ExplodeMissile;
749  bolt->s.eType = ET_MISSILE;
750  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
751  bolt->s.weapon = WP_LOCKBLOB_LAUNCHER;
752  bolt->s.generic1 = self->s.generic1; //weaponMode
753  bolt->r.ownerNum = self->s.number;
754  bolt->parent = self;
755  bolt->damage = 0;
756  bolt->splashDamage = 0;
757  bolt->splashRadius = 0;
758  bolt->clipmask = MASK_SHOT;
759  bolt->target_ent = NULL;
760
761  bolt->s.pos.trType = TR_GRAVITY;
762  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
763  VectorCopy( start, bolt->s.pos.trBase );
764  VectorScale( dir, LOCKBLOB_SPEED, bolt->s.pos.trDelta );
765  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
766  VectorCopy( start, bolt->r.currentOrigin );
767
768  return bolt;
769}
770
771/*
772=================
773fire_bounceBall
774=================
775*/
776gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir )
777{
778  gentity_t *bolt;
779
780  VectorNormalize ( dir );
781
782  bolt = G_Spawn( );
783  bolt->classname = "bounceball";
784  bolt->nextthink = level.time + 3000;
785  bolt->think = G_ExplodeMissile;
786  bolt->s.eType = ET_MISSILE;
787  bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
788  bolt->s.weapon = WP_ALEVEL3_UPG;
789  bolt->s.generic1 = self->s.generic1; //weaponMode
790  bolt->r.ownerNum = self->s.number;
791  bolt->parent = self;
792  bolt->damage = LEVEL3_BOUNCEBALL_DMG;
793  bolt->splashDamage = LEVEL3_BOUNCEBALL_DMG;
794  bolt->splashRadius = LEVEL3_BOUNCEBALL_RADIUS;
795  bolt->methodOfDeath = MOD_LEVEL3_BOUNCEBALL;
796  bolt->splashMethodOfDeath = MOD_LEVEL3_BOUNCEBALL;
797  bolt->clipmask = MASK_SHOT;
798  bolt->target_ent = NULL;
799
800  bolt->s.pos.trType = TR_GRAVITY;
801  bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame
802  VectorCopy( start, bolt->s.pos.trBase );
803  VectorScale( dir, LEVEL3_BOUNCEBALL_SPEED, bolt->s.pos.trDelta );
804  SnapVector( bolt->s.pos.trDelta );      // save net bandwidth
805  VectorCopy( start, bolt->r.currentOrigin );
806  /*bolt->s.eFlags |= EF_BOUNCE;*/
807
808  return bolt;
809}
Note: See TracBrowser for help on using the browser.