codemp/game/g_weapon.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // g_weapon.c 
00004 // perform the server side effects of a weapon firing
00005 
00006 #include "g_local.h"
00007 #include "be_aas.h"
00008 #include "bg_saga.h"
00009 #include "../ghoul2/G2.h"
00010 #include "q_shared.h"
00011 
00012 static  float   s_quadFactor;
00013 static  vec3_t  forward, vright, up;
00014 static  vec3_t  muzzle;
00015 
00016 // Bryar Pistol
00017 //--------
00018 #define BRYAR_PISTOL_VEL                        1600
00019 #define BRYAR_PISTOL_DAMAGE                     10
00020 #define BRYAR_CHARGE_UNIT                       200.0f  // bryar charging gives us one more unit every 200ms--if you change this, you'll have to do the same in bg_pmove
00021 #define BRYAR_ALT_SIZE                          1.0f
00022 
00023 // E11 Blaster
00024 //---------
00025 #define BLASTER_SPREAD                          1.6f//1.2f
00026 #define BLASTER_VELOCITY                        2300
00027 #define BLASTER_DAMAGE                          20
00028 
00029 // Tenloss Disruptor
00030 //----------
00031 #define DISRUPTOR_MAIN_DAMAGE                   30 //40
00032 #define DISRUPTOR_MAIN_DAMAGE_SIEGE             50
00033 #define DISRUPTOR_NPC_MAIN_DAMAGE_CUT   0.25f
00034 
00035 #define DISRUPTOR_ALT_DAMAGE                    100 //125
00036 #define DISRUPTOR_NPC_ALT_DAMAGE_CUT    0.2f
00037 #define DISRUPTOR_ALT_TRACES                    3               // can go through a max of 3 damageable(sp?) entities
00038 #define DISRUPTOR_CHARGE_UNIT                   50.0f   // distruptor charging gives us one more unit every 50ms--if you change this, you'll have to do the same in bg_pmove
00039 
00040 // Wookiee Bowcaster
00041 //----------
00042 #define BOWCASTER_DAMAGE                        50
00043 #define BOWCASTER_VELOCITY                      1300
00044 #define BOWCASTER_SPLASH_DAMAGE         0
00045 #define BOWCASTER_SPLASH_RADIUS         0
00046 #define BOWCASTER_SIZE                          2
00047 
00048 #define BOWCASTER_ALT_SPREAD            5.0f
00049 #define BOWCASTER_VEL_RANGE                     0.3f
00050 #define BOWCASTER_CHARGE_UNIT           200.0f  // bowcaster charging gives us one more unit every 200ms--if you change this, you'll have to do the same in bg_pmove
00051 
00052 // Heavy Repeater
00053 //----------
00054 #define REPEATER_SPREAD                         1.4f
00055 #define REPEATER_DAMAGE                         14
00056 #define REPEATER_VELOCITY                       1600
00057 
00058 #define REPEATER_ALT_SIZE                               3       // half of bbox size
00059 #define REPEATER_ALT_DAMAGE                             60
00060 #define REPEATER_ALT_SPLASH_DAMAGE              60
00061 #define REPEATER_ALT_SPLASH_RADIUS              128
00062 #define REPEATER_ALT_SPLASH_RAD_SIEGE   80
00063 #define REPEATER_ALT_VELOCITY                   1100
00064 
00065 // DEMP2
00066 //----------
00067 #define DEMP2_DAMAGE                            35
00068 #define DEMP2_VELOCITY                          1800
00069 #define DEMP2_SIZE                                      2               // half of bbox size
00070 
00071 #define DEMP2_ALT_DAMAGE                        8 //12          // does 12, 36, 84 at each of the 3 charge levels.
00072 #define DEMP2_CHARGE_UNIT                       700.0f  // demp2 charging gives us one more unit every 700ms--if you change this, you'll have to do the same in bg_weapons
00073 #define DEMP2_ALT_RANGE                         4096
00074 #define DEMP2_ALT_SPLASHRADIUS          256
00075 
00076 // Golan Arms Flechette
00077 //---------
00078 #define FLECHETTE_SHOTS                         5
00079 #define FLECHETTE_SPREAD                        4.0f
00080 #define FLECHETTE_DAMAGE                        12//15
00081 #define FLECHETTE_VEL                           3500
00082 #define FLECHETTE_SIZE                          1
00083 #define FLECHETTE_MINE_RADIUS_CHECK     256
00084 #define FLECHETTE_ALT_DAMAGE            60
00085 #define FLECHETTE_ALT_SPLASH_DAM        60
00086 #define FLECHETTE_ALT_SPLASH_RAD        128
00087 
00088 // Personal Rocket Launcher
00089 //---------
00090 #define ROCKET_VELOCITY                         900
00091 #define ROCKET_DAMAGE                           100
00092 #define ROCKET_SPLASH_DAMAGE            100
00093 #define ROCKET_SPLASH_RADIUS            160
00094 #define ROCKET_SIZE                                     3
00095 #define ROCKET_ALT_THINK_TIME           100
00096 
00097 // Concussion Rifle
00098 //---------
00099 //primary
00100 //man, this thing is too absurdly powerful. having to
00101 //slash the values way down from sp.
00102 #define CONC_VELOCITY                           3000
00103 #define CONC_DAMAGE                                     75 //150
00104 #define CONC_NPC_DAMAGE_EASY            40
00105 #define CONC_NPC_DAMAGE_NORMAL          80
00106 #define CONC_NPC_DAMAGE_HARD            100
00107 #define CONC_SPLASH_DAMAGE                      40 //50
00108 #define CONC_SPLASH_RADIUS                      200 //300
00109 //alt
00110 #define CONC_ALT_DAMAGE                         25 //100
00111 #define CONC_ALT_NPC_DAMAGE_EASY        20
00112 #define CONC_ALT_NPC_DAMAGE_MEDIUM      35
00113 #define CONC_ALT_NPC_DAMAGE_HARD        50
00114 
00115 // Stun Baton
00116 //--------------
00117 #define STUN_BATON_DAMAGE                       20
00118 #define STUN_BATON_ALT_DAMAGE           20
00119 #define STUN_BATON_RANGE                        8
00120 
00121 // Melee
00122 //--------------
00123 #define MELEE_SWING1_DAMAGE                     10
00124 #define MELEE_SWING2_DAMAGE                     12
00125 #define MELEE_RANGE                                     8
00126 
00127 // ATST Main Gun
00128 //--------------
00129 #define ATST_MAIN_VEL                           4000    // 
00130 #define ATST_MAIN_DAMAGE                        25              // 
00131 #define ATST_MAIN_SIZE                          3               // make it easier to hit things
00132 
00133 // ATST Side Gun
00134 //---------------
00135 #define ATST_SIDE_MAIN_DAMAGE                           75
00136 #define ATST_SIDE_MAIN_VELOCITY                         1300
00137 #define ATST_SIDE_MAIN_NPC_DAMAGE_EASY          30
00138 #define ATST_SIDE_MAIN_NPC_DAMAGE_NORMAL        40
00139 #define ATST_SIDE_MAIN_NPC_DAMAGE_HARD          50
00140 #define ATST_SIDE_MAIN_SIZE                                     4
00141 #define ATST_SIDE_MAIN_SPLASH_DAMAGE            10      // yeah, pretty small, either zero out or make it worth having?
00142 #define ATST_SIDE_MAIN_SPLASH_RADIUS            16      // yeah, pretty small, either zero out or make it worth having?
00143 
00144 #define ATST_SIDE_ALT_VELOCITY                          1100
00145 #define ATST_SIDE_ALT_NPC_VELOCITY                      600
00146 #define ATST_SIDE_ALT_DAMAGE                            130
00147 
00148 #define ATST_SIDE_ROCKET_NPC_DAMAGE_EASY        30
00149 #define ATST_SIDE_ROCKET_NPC_DAMAGE_NORMAL      50
00150 #define ATST_SIDE_ROCKET_NPC_DAMAGE_HARD        90
00151 
00152 #define ATST_SIDE_ALT_SPLASH_DAMAGE                     130
00153 #define ATST_SIDE_ALT_SPLASH_RADIUS                     200
00154 #define ATST_SIDE_ALT_ROCKET_SIZE                       5
00155 #define ATST_SIDE_ALT_ROCKET_SPLASH_SCALE       0.5f    // scales splash for NPC's
00156 
00157 extern qboolean G_BoxInBounds( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t boundsMins, vec3_t boundsMaxs );
00158 extern qboolean G_HeavyMelee( gentity_t *attacker );
00159 extern void Jedi_Decloak( gentity_t *self );
00160 
00161 static void WP_FireEmplaced( gentity_t *ent, qboolean altFire );
00162 
00163 void laserTrapStick( gentity_t *ent, vec3_t endpos, vec3_t normal );
00164 
00165 void touch_NULL( gentity_t *ent, gentity_t *other, trace_t *trace )
00166 {
00167 
00168 }
00169 
00170 void laserTrapExplode( gentity_t *self );
00171 void RocketDie(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
00172 
00173 //We should really organize weapon data into tables or parse from the ext data so we have accurate info for this,
00174 float WP_SpeedOfMissileForWeapon( int wp, qboolean alt_fire )
00175 {
00176         return 500;
00177 }
00178 
00179 //-----------------------------------------------------------------------------
00180 void W_TraceSetStart( gentity_t *ent, vec3_t start, vec3_t mins, vec3_t maxs )
00181 //-----------------------------------------------------------------------------
00182 {
00183         //make sure our start point isn't on the other side of a wall
00184         trace_t tr;
00185         vec3_t  entMins;
00186         vec3_t  entMaxs;
00187         vec3_t  eyePoint;
00188 
00189         VectorAdd( ent->r.currentOrigin, ent->r.mins, entMins );
00190         VectorAdd( ent->r.currentOrigin, ent->r.maxs, entMaxs );
00191 
00192         if ( G_BoxInBounds( start, mins, maxs, entMins, entMaxs ) )
00193         {
00194                 return;
00195         }
00196 
00197         if ( !ent->client )
00198         {
00199                 return;
00200         }
00201 
00202         VectorCopy( ent->s.pos.trBase, eyePoint);
00203         eyePoint[2] += ent->client->ps.viewheight;
00204                 
00205         trap_Trace( &tr, eyePoint, mins, maxs, start, ent->s.number, MASK_SOLID|CONTENTS_SHOTCLIP );
00206 
00207         if ( tr.startsolid || tr.allsolid )
00208         {
00209                 return;
00210         }
00211 
00212         if ( tr.fraction < 1.0f )
00213         {
00214                 VectorCopy( tr.endpos, start );
00215         }
00216 }
00217 
00218 
00219 /*
00220 ----------------------------------------------
00221         PLAYER WEAPONS
00222 ----------------------------------------------
00223 */
00224 
00225 /*
00226 ======================================================================
00227 
00228 BRYAR PISTOL
00229 
00230 ======================================================================
00231 */
00232 
00233 //----------------------------------------------
00234 static void WP_FireBryarPistol( gentity_t *ent, qboolean altFire )
00235 //---------------------------------------------------------
00236 {
00237         int damage = BRYAR_PISTOL_DAMAGE;
00238         int count;
00239 
00240         gentity_t       *missile = CreateMissile( muzzle, forward, BRYAR_PISTOL_VEL, 10000, ent, altFire );
00241 
00242         missile->classname = "bryar_proj";
00243         missile->s.weapon = WP_BRYAR_PISTOL;
00244 
00245         if ( altFire )
00246         {
00247                 float boxSize = 0;
00248 
00249                 count = ( level.time - ent->client->ps.weaponChargeTime ) / BRYAR_CHARGE_UNIT;
00250 
00251                 if ( count < 1 )
00252                 {
00253                         count = 1;
00254                 }
00255                 else if ( count > 5 )
00256                 {
00257                         count = 5;
00258                 }
00259 
00260                 if (count > 1)
00261                 {
00262                         damage *= (count*1.7);
00263                 }
00264                 else
00265                 {
00266                         damage *= (count*1.5);
00267                 }
00268 
00269                 missile->s.generic1 = count; // The missile will then render according to the charge level.
00270 
00271                 boxSize = BRYAR_ALT_SIZE*(count*0.5);
00272 
00273                 VectorSet( missile->r.maxs, boxSize, boxSize, boxSize );
00274                 VectorSet( missile->r.mins, -boxSize, -boxSize, -boxSize );
00275         }
00276 
00277         missile->damage = damage;
00278         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00279         if (altFire)
00280         {
00281                 missile->methodOfDeath = MOD_BRYAR_PISTOL_ALT;
00282         }
00283         else
00284         {
00285                 missile->methodOfDeath = MOD_BRYAR_PISTOL;
00286         }
00287         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00288 
00289         // we don't want it to bounce forever
00290         missile->bounceCount = 8;
00291 }
00292 
00293 /*
00294 ======================================================================
00295 
00296 GENERIC
00297 
00298 ======================================================================
00299 */
00300 
00301 //---------------------------------------------------------
00302 void WP_FireTurretMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean altFire, int damage, int velocity, int mod, gentity_t *ignore )
00303 //---------------------------------------------------------
00304 {
00305         gentity_t *missile;
00306 
00307         missile = CreateMissile( start, dir, velocity, 10000, ent, altFire );
00308 
00309         missile->classname = "generic_proj";
00310         missile->s.weapon = WP_TURRET;
00311 
00312         missile->damage = damage;
00313         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00314         missile->methodOfDeath = mod;
00315         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00316 
00317         if (ignore)
00318         {
00319                 missile->passThroughNum = ignore->s.number+1;
00320         }
00321 
00322         // we don't want it to bounce forever
00323         missile->bounceCount = 8;
00324 }
00325 
00326 //Currently only the seeker drone uses this, but it might be useful for other things as well.
00327 
00328 //---------------------------------------------------------
00329 void WP_FireGenericBlasterMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean altFire, int damage, int velocity, int mod )
00330 //---------------------------------------------------------
00331 {
00332         gentity_t *missile;
00333 
00334         missile = CreateMissile( start, dir, velocity, 10000, ent, altFire );
00335 
00336         missile->classname = "generic_proj";
00337         missile->s.weapon = WP_BRYAR_PISTOL;
00338 
00339         missile->damage = damage;
00340         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00341         missile->methodOfDeath = mod;
00342         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00343 
00344         // we don't want it to bounce forever
00345         missile->bounceCount = 8;
00346 }
00347 
00348 /*
00349 ======================================================================
00350 
00351 BLASTER
00352 
00353 ======================================================================
00354 */
00355 
00356 //---------------------------------------------------------
00357 void WP_FireBlasterMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean altFire )
00358 //---------------------------------------------------------
00359 {
00360         int velocity    = BLASTER_VELOCITY;
00361         int     damage          = BLASTER_DAMAGE;
00362         gentity_t *missile;
00363 
00364         if (ent->s.eType == ET_NPC)
00365         { //animent
00366                 damage = 10;
00367         }
00368 
00369         missile = CreateMissile( start, dir, velocity, 10000, ent, altFire );
00370 
00371         missile->classname = "blaster_proj";
00372         missile->s.weapon = WP_BLASTER;
00373 
00374         missile->damage = damage;
00375         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00376         missile->methodOfDeath = MOD_BLASTER;
00377         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00378 
00379         // we don't want it to bounce forever
00380         missile->bounceCount = 8;
00381 }
00382 
00383 //---------------------------------------------------------
00384 void WP_FireTurboLaserMissile( gentity_t *ent, vec3_t start, vec3_t dir )
00385 //---------------------------------------------------------
00386 {
00387         int velocity    = ent->mass; //FIXME: externalize
00388         gentity_t *missile;
00389 
00390         missile = CreateMissile( start, dir, velocity, 10000, ent, qfalse );
00391         
00392         //use a custom shot effect
00393         missile->s.otherEntityNum2 = ent->genericValue14;
00394         //use a custom impact effect
00395         missile->s.emplacedOwner = ent->genericValue15;
00396 
00397         missile->classname = "turbo_proj";
00398         missile->s.weapon = WP_TURRET;
00399 
00400         missile->damage = ent->damage;          //FIXME: externalize
00401         missile->splashDamage = ent->splashDamage;      //FIXME: externalize
00402         missile->splashRadius = ent->splashRadius;      //FIXME: externalize
00403         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00404         missile->methodOfDeath = MOD_TURBLAST; //count as a heavy weap
00405         missile->splashMethodOfDeath = MOD_TURBLAST;// ?SPLASH;
00406         missile->clipmask = MASK_SHOT;
00407 
00408         // we don't want it to bounce forever
00409         missile->bounceCount = 8;
00410 
00411         //set veh as cgame side owner for purpose of fx overrides
00412         missile->s.owner = ent->s.number;
00413 
00414         //don't let them last forever
00415         missile->think = G_FreeEntity;
00416         missile->nextthink = level.time + 5000;//at 20000 speed, that should be more than enough
00417 }
00418 
00419 //---------------------------------------------------------
00420 void WP_FireEmplacedMissile( gentity_t *ent, vec3_t start, vec3_t dir, qboolean altFire, gentity_t *ignore )
00421 //---------------------------------------------------------
00422 {
00423         int velocity    = BLASTER_VELOCITY;
00424         int     damage          = BLASTER_DAMAGE;
00425         gentity_t *missile;
00426 
00427         missile = CreateMissile( start, dir, velocity, 10000, ent, altFire );
00428 
00429         missile->classname = "emplaced_gun_proj";
00430         missile->s.weapon = WP_TURRET;//WP_EMPLACED_GUN;
00431 
00432         missile->activator = ignore;
00433 
00434         missile->damage = damage;
00435         missile->dflags = (DAMAGE_DEATH_KNOCKBACK|DAMAGE_HEAVY_WEAP_CLASS);
00436         missile->methodOfDeath = MOD_VEHICLE;
00437         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00438 
00439         if (ignore)
00440         {
00441                 missile->passThroughNum = ignore->s.number+1;
00442         }
00443 
00444         // we don't want it to bounce forever
00445         missile->bounceCount = 8;
00446 }
00447 
00448 //---------------------------------------------------------
00449 static void WP_FireBlaster( gentity_t *ent, qboolean altFire )
00450 //---------------------------------------------------------
00451 {
00452         vec3_t  dir, angs;
00453 
00454         vectoangles( forward, angs );
00455 
00456         if ( altFire )
00457         {
00458                 // add some slop to the alt-fire direction
00459                 angs[PITCH] += crandom() * BLASTER_SPREAD;
00460                 angs[YAW]       += crandom() * BLASTER_SPREAD;
00461         }
00462 
00463         AngleVectors( angs, dir, NULL, NULL );
00464 
00465         // FIXME: if temp_org does not have clear trace to inside the bbox, don't shoot!
00466         WP_FireBlasterMissile( ent, muzzle, dir, altFire );
00467 }
00468 
00469 
00470 
00471 int G_GetHitLocation(gentity_t *target, vec3_t ppoint);
00472 
00473 /*
00474 ======================================================================
00475 
00476 DISRUPTOR
00477 
00478 ======================================================================
00479 */
00480 //---------------------------------------------------------
00481 static void WP_DisruptorMainFire( gentity_t *ent )
00482 //---------------------------------------------------------
00483 {
00484         int                     damage = DISRUPTOR_MAIN_DAMAGE;
00485         qboolean        render_impact = qtrue;
00486         vec3_t          start, end;
00487         trace_t         tr;
00488         gentity_t       *traceEnt, *tent;
00489         float           shotRange = 8192;
00490         int                     ignore, traces;
00491 
00492         if ( g_gametype.integer == GT_SIEGE )
00493         {
00494                 damage = DISRUPTOR_MAIN_DAMAGE_SIEGE;
00495         }
00496 
00497         memset(&tr, 0, sizeof(tr)); //to shut the compiler up
00498 
00499         VectorCopy( ent->client->ps.origin, start );
00500         start[2] += ent->client->ps.viewheight;//By eyes
00501 
00502         VectorMA( start, shotRange, forward, end );
00503 
00504         ignore = ent->s.number;
00505         traces = 0;
00506         while ( traces < 10 )
00507         {//need to loop this in case we hit a Jedi who dodges the shot
00508                 if (d_projectileGhoul2Collision.integer)
00509                 {
00510                         trap_G2Trace( &tr, start, NULL, NULL, end, ignore, MASK_SHOT, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );
00511                 }
00512                 else
00513                 {
00514                         trap_Trace( &tr, start, NULL, NULL, end, ignore, MASK_SHOT );
00515                 }
00516 
00517                 traceEnt = &g_entities[tr.entityNum];
00518 
00519                 if (d_projectileGhoul2Collision.integer && traceEnt->inuse && traceEnt->client)
00520                 { //g2 collision checks -rww
00521                         if (traceEnt->inuse && traceEnt->client && traceEnt->ghoul2)
00522                         { //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
00523                                 traceEnt->client->g2LastSurfaceHit = tr.surfaceFlags;
00524                                 traceEnt->client->g2LastSurfaceTime = level.time;
00525                         }
00526 
00527                         if (traceEnt->ghoul2)
00528                         {
00529                                 tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
00530                         }
00531                 }
00532 
00533                 if (traceEnt && traceEnt->client && traceEnt->client->ps.duelInProgress &&
00534                         traceEnt->client->ps.duelIndex != ent->s.number)
00535                 {
00536                         VectorCopy( tr.endpos, start );
00537                         ignore = tr.entityNum;
00538                         traces++;
00539                         continue;
00540                 }
00541 
00542                 if ( Jedi_DodgeEvasion( traceEnt, ent, &tr, G_GetHitLocation(traceEnt, tr.endpos) ) )
00543                 {//act like we didn't even hit him
00544                         VectorCopy( tr.endpos, start );
00545                         ignore = tr.entityNum;
00546                         traces++;
00547                         continue;
00548                 }
00549                 else if (traceEnt && traceEnt->client && traceEnt->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_3)
00550                 {
00551                         if (WP_SaberCanBlock(traceEnt, tr.endpos, 0, MOD_DISRUPTOR, qtrue, 0))
00552                         { //broadcast and stop the shot because it was blocked
00553                                 gentity_t *te = NULL;
00554 
00555                                 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_MAIN_SHOT );
00556                                 VectorCopy( muzzle, tent->s.origin2 );
00557                                 tent->s.eventParm = ent->s.number;
00558 
00559                                 te = G_TempEntity( tr.endpos, EV_SABER_BLOCK );
00560                                 VectorCopy(tr.endpos, te->s.origin);
00561                                 VectorCopy(tr.plane.normal, te->s.angles);
00562                                 if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
00563                                 {
00564                                         te->s.angles[1] = 1;
00565                                 }
00566                                 te->s.eventParm = 0;
00567                                 te->s.weapon = 0;//saberNum
00568                                 te->s.legsAnim = 0;//bladeNum
00569 
00570                                 return;
00571                         }
00572                 }
00573                 else if ( (traceEnt->flags&FL_SHIELDED) )
00574                 {//stopped cold
00575                         return;
00576                 }
00577                 //a Jedi is not dodging this shot
00578                 break;
00579         }
00580 
00581         if ( tr.surfaceFlags & SURF_NOIMPACT ) 
00582         {
00583                 render_impact = qfalse;
00584         }
00585 
00586         // always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
00587         tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_MAIN_SHOT );
00588         VectorCopy( muzzle, tent->s.origin2 );
00589         tent->s.eventParm = ent->s.number;
00590 
00591         traceEnt = &g_entities[tr.entityNum];
00592 
00593         if ( render_impact )
00594         {
00595                 if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage )
00596                 {
00597                         if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) 
00598                         {
00599                                 ent->client->accuracy_hits++;
00600                         } 
00601 
00602                         G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NORMAL, MOD_DISRUPTOR );
00603                         
00604                         tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_HIT );
00605                         tent->s.eventParm = DirToByte( tr.plane.normal );
00606                         if (traceEnt->client)
00607                         {
00608                                 tent->s.weapon = 1;
00609                         }
00610                 }
00611                 else 
00612                 {
00613                          // Hmmm, maybe don't make any marks on things that could break
00614                         tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_MISS );
00615                         tent->s.eventParm = DirToByte( tr.plane.normal );
00616                         tent->s.weapon = 1;
00617                 }
00618         }
00619 }
00620 
00621 
00622 qboolean G_CanDisruptify(gentity_t *ent)
00623 {
00624         if (!ent || !ent->inuse || !ent->client || ent->s.eType != ET_NPC ||
00625                 ent->s.NPC_class != CLASS_VEHICLE || !ent->m_pVehicle)
00626         { //not vehicle
00627                 return qtrue;
00628         }
00629 
00630         if (ent->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
00631         { //animal is only type that can be disintigeiteigerated
00632                 return qtrue;
00633         }
00634 
00635         //don't do it to any other veh
00636         return qfalse;
00637 }
00638 
00639 //---------------------------------------------------------
00640 void WP_DisruptorAltFire( gentity_t *ent )
00641 //---------------------------------------------------------
00642 {
00643         int                     damage = 0, skip;
00644         qboolean        render_impact = qtrue;
00645         vec3_t          start, end;
00646         vec3_t          muzzle2;
00647         trace_t         tr;
00648         gentity_t       *traceEnt, *tent;
00649         float           shotRange = 8192.0f;
00650         int                     i;
00651         int                     count, maxCount = 60;
00652         int                     traces = DISRUPTOR_ALT_TRACES;
00653         qboolean        fullCharge = qfalse;
00654 
00655         damage = DISRUPTOR_ALT_DAMAGE-30;
00656 
00657         VectorCopy( muzzle, muzzle2 ); // making a backup copy
00658 
00659         if (ent->client)
00660         {
00661                 VectorCopy( ent->client->ps.origin, start );
00662                 start[2] += ent->client->ps.viewheight;//By eyes
00663 
00664                 count = ( level.time - ent->client->ps.weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT;
00665                 if ( g_gametype.integer == GT_SIEGE )
00666                 {//maybe a full alt-charge should be a *bit* more dangerous in Siege mode?
00667                         //maxCount = ceil((200.0f-(float)damage)/2.0f);//cap at 200 damage total
00668                         maxCount = 200;//the previous line ALWAYS evaluated to 135 - was that on purpose?
00669                 }
00670         }
00671         else
00672         {
00673                 VectorCopy( ent->r.currentOrigin, start );
00674                 start[2] += 24;
00675 
00676                 count = ( 100 ) / DISRUPTOR_CHARGE_UNIT;
00677         }
00678 
00679         count *= 2;
00680 
00681         if ( count < 1 )
00682         {
00683                 count = 1;
00684         }
00685         else if ( count >= maxCount )
00686         {
00687                 count = maxCount;
00688                 fullCharge = qtrue;
00689         }
00690 
00691         // more powerful charges go through more things
00692         if ( count < 10 )
00693         {
00694                 traces = 1;
00695         }
00696         else if ( count < 20 )
00697         {
00698                 traces = 2;
00699         }
00700 
00701         damage += count;
00702         
00703         skip = ent->s.number;
00704 
00705         for (i = 0; i < traces; i++ )
00706         {
00707                 VectorMA( start, shotRange, forward, end );
00708 
00709                 if (d_projectileGhoul2Collision.integer)
00710                 {
00711                         trap_G2Trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );
00712                 }
00713                 else
00714                 {
00715                         trap_Trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT );
00716                 }
00717 
00718                 traceEnt = &g_entities[tr.entityNum];
00719 
00720                 if (d_projectileGhoul2Collision.integer && traceEnt->inuse && traceEnt->client)
00721                 { //g2 collision checks -rww
00722                         if (traceEnt->inuse && traceEnt->client && traceEnt->ghoul2)
00723                         { //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
00724                                 traceEnt->client->g2LastSurfaceHit = tr.surfaceFlags;
00725                                 traceEnt->client->g2LastSurfaceTime = level.time;
00726                         }
00727 
00728                         if (traceEnt->ghoul2)
00729                         {
00730                                 tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
00731                         }
00732                 }
00733 
00734                 if ( tr.surfaceFlags & SURF_NOIMPACT ) 
00735                 {
00736                         render_impact = qfalse;
00737                 }
00738 
00739                 if (traceEnt && traceEnt->client && traceEnt->client->ps.duelInProgress &&
00740                         traceEnt->client->ps.duelIndex != ent->s.number)
00741                 {
00742                         skip = tr.entityNum;
00743                         VectorCopy(tr.endpos, start);
00744                         continue;
00745                 }
00746 
00747                 if (Jedi_DodgeEvasion(traceEnt, ent, &tr, G_GetHitLocation(traceEnt, tr.endpos)))
00748                 {
00749                         skip = tr.entityNum;
00750                         VectorCopy(tr.endpos, start);
00751                         continue;
00752                 }
00753                 else if (traceEnt && traceEnt->client && traceEnt->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_3)
00754                 {
00755                         if (WP_SaberCanBlock(traceEnt, tr.endpos, 0, MOD_DISRUPTOR_SNIPER, qtrue, 0))
00756                         { //broadcast and stop the shot because it was blocked
00757                                 gentity_t *te = NULL;
00758 
00759                                 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_SHOT );
00760                                 VectorCopy( muzzle, tent->s.origin2 );
00761                                 tent->s.shouldtarget = fullCharge;
00762                                 tent->s.eventParm = ent->s.number;
00763 
00764                                 te = G_TempEntity( tr.endpos, EV_SABER_BLOCK );
00765                                 VectorCopy(tr.endpos, te->s.origin);
00766                                 VectorCopy(tr.plane.normal, te->s.angles);
00767                                 if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
00768                                 {
00769                                         te->s.angles[1] = 1;
00770                                 }
00771                                 te->s.eventParm = 0;
00772                                 te->s.weapon = 0;//saberNum
00773                                 te->s.legsAnim = 0;//bladeNum
00774 
00775                                 return;
00776                         }
00777                 }
00778 
00779                 // always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
00780                 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_SHOT );
00781                 VectorCopy( muzzle, tent->s.origin2 );
00782                 tent->s.shouldtarget = fullCharge;
00783                 tent->s.eventParm = ent->s.number;
00784 
00785                 // If the beam hits a skybox, etc. it would look foolish to add impact effects
00786                 if ( render_impact ) 
00787                 {
00788                         if ( traceEnt->takedamage && traceEnt->client )
00789                         {
00790                                 tent->s.otherEntityNum = traceEnt->s.number;
00791 
00792                                 // Create a simple impact type mark
00793                                 tent = G_TempEntity(tr.endpos, EV_MISSILE_MISS);
00794                                 tent->s.eventParm = DirToByte(tr.plane.normal);
00795                                 tent->s.eFlags |= EF_ALT_FIRING;
00796         
00797                                 if ( LogAccuracyHit( traceEnt, ent )) 
00798                                 {
00799                                         if (ent->client)
00800                                         {
00801                                                 ent->client->accuracy_hits++;
00802                                         }
00803                                 }
00804                         } 
00805                         else 
00806                         {
00807                                  if ( traceEnt->r.svFlags & SVF_GLASS_BRUSH 
00808                                                 || traceEnt->takedamage 
00809                                                 || traceEnt->s.eType == ET_MOVER )
00810                                  {
00811                                         if ( traceEnt->takedamage )
00812                                         {
00813                                                 G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 
00814                                                                 DAMAGE_NO_KNOCKBACK, MOD_DISRUPTOR_SNIPER );
00815 
00816                                                 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_HIT );
00817                                                 tent->s.eventParm = DirToByte( tr.plane.normal );
00818                                         }
00819                                  }
00820                                  else
00821                                  {
00822                                          // Hmmm, maybe don't make any marks on things that could break
00823                                         tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_MISS );
00824                                         tent->s.eventParm = DirToByte( tr.plane.normal );
00825                                  }
00826                                 break; // and don't try any more traces
00827                         }
00828 
00829                         if ( (traceEnt->flags&FL_SHIELDED) )
00830                         {//stops us cold
00831                                 break;
00832                         }
00833 
00834                         if ( traceEnt->takedamage )
00835                         {
00836                                 vec3_t preAng;
00837                                 int preHealth = traceEnt->health;
00838                                 int preLegs = 0;
00839                                 int preTorso = 0;
00840 
00841                                 if (traceEnt->client)
00842                                 {
00843                                         preLegs = traceEnt->client->ps.legsAnim;
00844                                         preTorso = traceEnt->client->ps.torsoAnim;
00845                                         VectorCopy(traceEnt->client->ps.viewangles, preAng);
00846                                 }
00847 
00848                                 G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_DISRUPTOR_SNIPER );
00849 
00850                                 if (traceEnt->client && preHealth > 0 && traceEnt->health <= 0 && fullCharge &&
00851                                         G_CanDisruptify(traceEnt))
00852                                 { //was killed by a fully charged sniper shot, so disintegrate
00853                                         VectorCopy(preAng, traceEnt->client->ps.viewangles);
00854 
00855                                         traceEnt->client->ps.eFlags |= EF_DISINTEGRATION;
00856                                         VectorCopy(tr.endpos, traceEnt->client->ps.lastHitLoc);
00857 
00858                                         traceEnt->client->ps.legsAnim = preLegs;
00859                                         traceEnt->client->ps.torsoAnim = preTorso;
00860 
00861                                         traceEnt->r.contents = 0;
00862 
00863                                         VectorClear(traceEnt->client->ps.velocity);
00864                                 }
00865 
00866                                 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_HIT );
00867                                 tent->s.eventParm = DirToByte( tr.plane.normal );
00868                                 if (traceEnt->client)
00869                                 {
00870                                         tent->s.weapon = 1;
00871                                 }
00872                         }
00873                 }
00874                 else // not rendering impact, must be a skybox or other similar thing?
00875                 {
00876                         break; // don't try anymore traces
00877                 }
00878 
00879                 // Get ready for an attempt to trace through another person
00880                 VectorCopy( tr.endpos, muzzle );
00881                 VectorCopy( tr.endpos, start );
00882                 skip = tr.entityNum;
00883         }
00884 }
00885 
00886 
00887 //---------------------------------------------------------
00888 static void WP_FireDisruptor( gentity_t *ent, qboolean altFire )
00889 //---------------------------------------------------------
00890 {
00891         if (!ent || !ent->client || ent->client->ps.zoomMode != 1)
00892         { //do not ever let it do the alt fire when not zoomed
00893                 altFire = qfalse;
00894         }
00895 
00896         if (ent && ent->s.eType == ET_NPC && !ent->client)
00897         { //special case for animents
00898                 WP_DisruptorAltFire( ent );
00899                 return;
00900         }
00901 
00902         if ( altFire )
00903         {
00904                 WP_DisruptorAltFire( ent );
00905         }
00906         else
00907         {
00908                 WP_DisruptorMainFire( ent );
00909         }
00910 }
00911 
00912 
00913 /*
00914 ======================================================================
00915 
00916 BOWCASTER
00917 
00918 ======================================================================
00919 */
00920 
00921 static void WP_BowcasterAltFire( gentity_t *ent )
00922 {
00923         int     damage  = BOWCASTER_DAMAGE;
00924 
00925         gentity_t *missile = CreateMissile( muzzle, forward, BOWCASTER_VELOCITY, 10000, ent, qfalse);
00926 
00927         missile->classname = "bowcaster_proj";
00928         missile->s.weapon = WP_BOWCASTER;
00929 
00930         VectorSet( missile->r.maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
00931         VectorScale( missile->r.maxs, -1, missile->r.mins );
00932 
00933         missile->damage = damage;
00934         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00935         missile->methodOfDeath = MOD_BOWCASTER;
00936         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00937 
00938         missile->flags |= FL_BOUNCE;
00939         missile->bounceCount = 3;
00940 }
00941 
00942 //---------------------------------------------------------
00943 static void WP_BowcasterMainFire( gentity_t *ent )
00944 //---------------------------------------------------------
00945 {
00946         int                     damage  = BOWCASTER_DAMAGE, count;
00947         float           vel;
00948         vec3_t          angs, dir;
00949         gentity_t       *missile;
00950         int i;
00951 
00952         if (!ent->client)
00953         {
00954                 count = 1;
00955         }
00956         else
00957         {
00958                 count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT;
00959         }
00960 
00961         if ( count < 1 )
00962         {
00963                 count = 1;
00964         }
00965         else if ( count > 5 )
00966         {
00967                 count = 5;
00968         }
00969 
00970         if ( !(count & 1 ))
00971         {
00972                 // if we aren't odd, knock us down a level
00973                 count--;
00974         }
00975 
00976         //scale the damage down based on how many are about to be fired
00977         if (count <= 1)
00978         {
00979                 damage = 50;
00980         }
00981         else if (count == 2)
00982         {
00983                 damage = 45;
00984         }
00985         else if (count == 3)
00986         {
00987                 damage = 40;
00988         }
00989         else if (count == 4)
00990         {
00991                 damage = 35;
00992         }
00993         else
00994         {
00995                 damage = 30;
00996         }
00997 
00998         for (i = 0; i < count; i++ )
00999         {
01000                 // create a range of different velocities
01001                 vel = BOWCASTER_VELOCITY * ( crandom() * BOWCASTER_VEL_RANGE + 1.0f );
01002 
01003                 vectoangles( forward, angs );
01004 
01005                 // add some slop to the alt-fire direction
01006                 angs[PITCH] += crandom() * BOWCASTER_ALT_SPREAD * 0.2f;
01007                 angs[YAW]       += ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD );
01008                 
01009                 AngleVectors( angs, dir, NULL, NULL );
01010 
01011                 missile = CreateMissile( muzzle, dir, vel, 10000, ent, qtrue );
01012 
01013                 missile->classname = "bowcaster_alt_proj";
01014                 missile->s.weapon = WP_BOWCASTER;
01015 
01016                 VectorSet( missile->r.maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
01017                 VectorScale( missile->r.maxs, -1, missile->r.mins );
01018 
01019                 missile->damage = damage;
01020                 missile->dflags = DAMAGE_DEATH_KNOCKBACK;
01021                 missile->methodOfDeath = MOD_BOWCASTER;
01022                 missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
01023 
01024                 // we don't want it to bounce
01025                 missile->bounceCount = 0;
01026         }
01027 }
01028 
01029 //---------------------------------------------------------
01030 static void WP_FireBowcaster( gentity_t *ent, qboolean altFire )
01031 //---------------------------------------------------------
01032 {
01033         if ( altFire )
01034         {
01035                 WP_BowcasterAltFire( ent );
01036         }
01037         else
01038         {
01039                 WP_BowcasterMainFire( ent );
01040         }
01041 }
01042 
01043 
01044 
01045 /*
01046 ======================================================================
01047 
01048 REPEATER
01049 
01050 ======================================================================
01051 */
01052 
01053 //---------------------------------------------------------
01054 static void WP_RepeaterMainFire( gentity_t *ent, vec3_t dir )
01055 //---------------------------------------------------------
01056 {
01057         int     damage  = REPEATER_DAMAGE;
01058 
01059         gentity_t *missile = CreateMissile( muzzle, dir, REPEATER_VELOCITY, 10000, ent, qfalse );
01060 
01061         missile->classname = "repeater_proj";
01062         missile->s.weapon = WP_REPEATER;
01063 
01064         missile->damage = damage;
01065         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
01066         missile->methodOfDeath = MOD_REPEATER;
01067         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
01068 
01069         // we don't want it to bounce forever
01070         missile->bounceCount = 8;
01071 }
01072 
01073 //---------------------------------------------------------
01074 static void WP_RepeaterAltFire( gentity_t *ent )
01075 //---------------------------------------------------------
01076 {
01077         int     damage  = REPEATER_ALT_DAMAGE;
01078 
01079         gentity_t *missile = CreateMissile( muzzle, forward, REPEATER_ALT_VELOCITY, 10000, ent, qtrue );
01080 
01081         missile->classname = "repeater_alt_proj";
01082         missile->s.weapon = WP_REPEATER;
01083 
01084         VectorSet( missile->r.maxs, REPEATER_ALT_SIZE, REPEATER_ALT_SIZE, REPEATER_ALT_SIZE );
01085         VectorScale( missile->r.maxs, -1, missile->r.mins );
01086         missile->s.pos.trType = TR_GRAVITY;
01087         missile->s.pos.trDelta[2] += 40.0f; //give a slight boost in the upward direction
01088         missile->damage = damage;
01089         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
01090         missile->methodOfDeath = MOD_REPEATER_ALT;
01091         missile->splashMethodOfDeath = MOD_REPEATER_ALT_SPLASH;
01092         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
01093         missile->splashDamage = REPEATER_ALT_SPLASH_DAMAGE;
01094         if ( g_gametype.integer == GT_SIEGE )   // we've been having problems with this being too hyper-potent because of it's radius
01095         {
01096                 missile->splashRadius = REPEATER_ALT_SPLASH_RAD_SIEGE;
01097         }
01098         else
01099         {
01100                 missile->splashRadius = REPEATER_ALT_SPLASH_RADIUS;
01101         }
01102 
01103         // we don't want it to bounce forever
01104         missile->bounceCount = 8;
01105 }
01106 
01107 //---------------------------------------------------------
01108 static void WP_FireRepeater( gentity_t *ent, qboolean altFire )
01109 //---------------------------------------------------------
01110 {
01111         vec3_t  dir, angs;
01112 
01113         vectoangles( forward, angs );
01114 
01115         if ( altFire )
01116         {
01117                 WP_RepeaterAltFire( ent );
01118         }
01119         else
01120         {
01121                 // add some slop to the alt-fire direction
01122                 angs[PITCH] += crandom() * REPEATER_SPREAD;
01123                 angs[YAW]       += crandom() * REPEATER_SPREAD;
01124 
01125                 AngleVectors( angs, dir, NULL, NULL );
01126 
01127                 WP_RepeaterMainFire( ent, dir );
01128         }
01129 }
01130 
01131 
01132 /*
01133 ======================================================================
01134 
01135 DEMP2
01136 
01137 ======================================================================
01138 */
01139 
01140 static void WP_DEMP2_MainFire( gentity_t *ent )
01141 {
01142         int     damage  = DEMP2_DAMAGE;
01143 
01144         gentity_t *missile = CreateMissile( muzzle, forward, DEMP2_VELOCITY, 10000, ent, qfalse);
01145 
01146         missile->classname = "demp2_proj";
01147         missile->s.weapon = WP_DEMP2;
01148 
01149         VectorSet( missile->r.maxs, DEMP2_SIZE, DEMP2_SIZE, DEMP2_SIZE );
01150         VectorScale( missile->r.maxs, -1, missile->r.mins );
01151         missile->damage = damage;
01152         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
01153         missile->methodOfDeath = MOD_DEMP2;
01154         missile->clipmask = MASK_SHOT;
01155 
01156         // we don't want it to ever bounce
01157         missile->bounceCount = 0;
01158 }
01159 
01160 static gentity_t *ent_list[MAX_GENTITIES];
01161 
01162 void DEMP2_AltRadiusDamage( gentity_t *ent )
01163 {
01164         float           frac = ( level.time - ent->genericValue5 ) / 800.0f; // / 1600.0f; // synchronize with demp2 effect
01165         float           dist, radius, fact;
01166         gentity_t       *gent;
01167         int                     iEntityList[MAX_GENTITIES];
01168         gentity_t       *entityList[MAX_GENTITIES];
01169         gentity_t       *myOwner = NULL;
01170         int                     numListedEntities, i, e;
01171         vec3_t          mins, maxs;
01172         vec3_t          v, dir;
01173 
01174         if (ent->r.ownerNum >= 0 &&
01175                 ent->r.ownerNum < /*MAX_CLIENTS ... let npc's/shooters use it*/MAX_GENTITIES)
01176         {
01177                 myOwner = &g_entities[ent->r.ownerNum];
01178         }
01179 
01180         if (!myOwner || !myOwner->inuse || !myOwner->client)
01181         {
01182                 ent->think = G_FreeEntity;
01183                 ent->nextthink = level.time;
01184                 return;
01185         }
01186 
01187         frac *= frac * frac; // yes, this is completely ridiculous...but it causes the shell to grow slowly then "explode" at the end
01188         
01189         radius = frac * 200.0f; // 200 is max radius...the model is aprox. 100 units tall...the fx draw code mults. this by 2.
01190 
01191         fact = ent->count*0.6;
01192 
01193         if (fact < 1)
01194         {
01195                 fact = 1;
01196         }
01197 
01198         radius *= fact;
01199 
01200         for ( i = 0 ; i < 3 ; i++ ) 
01201         {
01202                 mins[i] = ent->r.currentOrigin[i] - radius;
01203                 maxs[i] = ent->r.currentOrigin[i] + radius;
01204         }
01205 
01206         numListedEntities = trap_EntitiesInBox( mins, maxs, iEntityList, MAX_GENTITIES );
01207 
01208         i = 0;
01209         while (i < numListedEntities)
01210         {
01211                 entityList[i] = &g_entities[iEntityList[i]];
01212                 i++;
01213         }
01214 
01215         for ( e = 0 ; e < numListedEntities ; e++ ) 
01216         {
01217                 gent = entityList[ e ];
01218 
01219                 if ( !gent || !gent->takedamage || !gent->r.contents )
01220                 {
01221                         continue;
01222                 }
01223 
01224                 // find the distance from the edge of the bounding box
01225                 for ( i = 0 ; i < 3 ; i++ ) 
01226                 {
01227                         if ( ent->r.currentOrigin[i] < gent->r.absmin[i] ) 
01228                         {
01229                                 v[i] = gent->r.absmin[i] - ent->r.currentOrigin[i];
01230                         } 
01231                         else if ( ent->r.currentOrigin[i] > gent->r.absmax[i] ) 
01232                         {
01233                                 v[i] = ent->r.currentOrigin[i] - gent->r.absmax[i];
01234                         } 
01235                         else 
01236                         {
01237                                 v[i] = 0;
01238                         }
01239                 }
01240 
01241                 // shape is an ellipsoid, so cut vertical distance in half`
01242                 v[2] *= 0.5f;
01243 
01244                 dist = VectorLength( v );
01245 
01246                 if ( dist >= radius ) 
01247                 {
01248                         // shockwave hasn't hit them yet
01249                         continue;
01250                 }
01251 
01252                 if (dist+(16*ent->