00001
00002
00003 #include "g_local.h"
00004 #include "w_saber.h"
00005 #include "q_shared.h"
00006
00007 #define MISSILE_PRESTEP_TIME 50
00008
00009 extern void laserTrapStick( gentity_t *ent, vec3_t endpos, vec3_t normal );
00010 extern void Jedi_Decloak( gentity_t *self );
00011
00012 #include "../namespace_begin.h"
00013 extern qboolean FighterIsLanded( Vehicle_t *pVeh, playerState_t *parentPS );
00014 #include "../namespace_end.h"
00015
00016
00017
00018
00019
00020
00021
00022
00023 float RandFloat(float min, float max);
00024 void G_ReflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward )
00025 {
00026 vec3_t bounce_dir;
00027 int i;
00028 float speed;
00029 gentity_t *owner = ent;
00030 int isowner = 0;
00031
00032 if ( ent->r.ownerNum )
00033 {
00034 owner = &g_entities[ent->r.ownerNum];
00035 }
00036
00037 if (missile->r.ownerNum == ent->s.number)
00038 {
00039 isowner = 1;
00040 }
00041
00042
00043 speed = VectorNormalize( missile->s.pos.trDelta );
00044
00045
00046 if ( &g_entities[missile->r.ownerNum] && missile->s.weapon != WP_SABER && missile->s.weapon != G2_MODEL_PART && !isowner )
00047 {
00048 VectorSubtract( g_entities[missile->r.ownerNum].r.currentOrigin, missile->r.currentOrigin, bounce_dir );
00049 VectorNormalize( bounce_dir );
00050 }
00051 else if (isowner)
00052 {
00053 vec3_t missile_dir;
00054
00055 speed *= 1.5;
00056
00057 VectorSubtract( missile->r.currentOrigin, ent->r.currentOrigin, missile_dir );
00058 VectorCopy( missile->s.pos.trDelta, bounce_dir );
00059 VectorScale( bounce_dir, DotProduct( forward, missile_dir ), bounce_dir );
00060 VectorNormalize( bounce_dir );
00061 }
00062 else
00063 {
00064 vec3_t missile_dir;
00065
00066 VectorSubtract( ent->r.currentOrigin, missile->r.currentOrigin, missile_dir );
00067 VectorCopy( missile->s.pos.trDelta, bounce_dir );
00068 VectorScale( bounce_dir, DotProduct( forward, missile_dir ), bounce_dir );
00069 VectorNormalize( bounce_dir );
00070 }
00071 for ( i = 0; i < 3; i++ )
00072 {
00073 bounce_dir[i] += RandFloat( -0.2f, 0.2f );
00074 }
00075
00076 VectorNormalize( bounce_dir );
00077 VectorScale( bounce_dir, speed, missile->s.pos.trDelta );
00078 missile->s.pos.trTime = level.time;
00079 VectorCopy( missile->r.currentOrigin, missile->s.pos.trBase );
00080 if ( missile->s.weapon != WP_SABER && missile->s.weapon != G2_MODEL_PART )
00081 {
00082 missile->r.ownerNum = ent->s.number;
00083 }
00084 if ( missile->s.weapon == WP_ROCKET_LAUNCHER )
00085 {
00086 missile->think = 0;
00087 missile->nextthink = 0;
00088 }
00089 }
00090
00091 void G_DeflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward )
00092 {
00093 vec3_t bounce_dir;
00094 int i;
00095 float speed;
00096 int isowner = 0;
00097 vec3_t missile_dir;
00098
00099 if (missile->r.ownerNum == ent->s.number)
00100 {
00101 isowner = 1;
00102 }
00103
00104
00105 speed = VectorNormalize( missile->s.pos.trDelta );
00106
00107 if (ent->client)
00108 {
00109
00110 AngleVectors(ent->client->ps.viewangles, missile_dir, 0, 0);
00111 VectorCopy(missile_dir, bounce_dir);
00112
00113 VectorScale( bounce_dir, DotProduct( forward, missile_dir ), bounce_dir );
00114 VectorNormalize( bounce_dir );
00115 }
00116 else
00117 {
00118 VectorCopy(forward, bounce_dir);
00119 VectorNormalize(bounce_dir);
00120 }
00121
00122 for ( i = 0; i < 3; i++ )
00123 {
00124 bounce_dir[i] += RandFloat( -1.0f, 1.0f );
00125 }
00126
00127 VectorNormalize( bounce_dir );
00128 VectorScale( bounce_dir, speed, missile->s.pos.trDelta );
00129 missile->s.pos.trTime = level.time;
00130 VectorCopy( missile->r.currentOrigin, missile->s.pos.trBase );
00131 if ( missile->s.weapon != WP_SABER && missile->s.weapon != G2_MODEL_PART )
00132 {
00133 missile->r.ownerNum = ent->s.number;
00134 }
00135 if ( missile->s.weapon == WP_ROCKET_LAUNCHER )
00136 {
00137 missile->think = 0;
00138 missile->nextthink = 0;
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147
00148 void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
00149 vec3_t velocity;
00150 float dot;
00151 int hitTime;
00152
00153
00154 hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
00155 BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
00156 dot = DotProduct( velocity, trace->plane.normal );
00157 VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
00158
00159
00160 if ( ent->flags & FL_BOUNCE_SHRAPNEL )
00161 {
00162 VectorScale( ent->s.pos.trDelta, 0.25f, ent->s.pos.trDelta );
00163 ent->s.pos.trType = TR_GRAVITY;
00164
00165
00166 if ( trace->plane.normal[2] > 0.7 && ent->s.pos.trDelta[2] < 40 )
00167 {
00168 G_SetOrigin( ent, trace->endpos );
00169 ent->nextthink = level.time + 100;
00170 return;
00171 }
00172 }
00173 else if ( ent->flags & FL_BOUNCE_HALF )
00174 {
00175 VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
00176
00177 if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 )
00178 {
00179 G_SetOrigin( ent, trace->endpos );
00180 return;
00181 }
00182 }
00183
00184 if (ent->s.weapon == WP_THERMAL)
00185 {
00186 G_Sound(ent, CHAN_BODY, G_SoundIndex(va("sound/weapons/thermal/bounce%i.wav", Q_irand(1, 2))));
00187 }
00188 else if (ent->s.weapon == WP_SABER)
00189 {
00190 G_Sound(ent, CHAN_BODY, G_SoundIndex(va("sound/weapons/saber/bounce%i.wav", Q_irand(1, 3))));
00191 }
00192 else if (ent->s.weapon == G2_MODEL_PART)
00193 {
00194
00195 }
00196
00197 VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
00198 VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
00199 ent->s.pos.trTime = level.time;
00200
00201 if (ent->bounceCount != -5)
00202 {
00203 ent->bounceCount--;
00204 }
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 void G_ExplodeMissile( gentity_t *ent ) {
00216 vec3_t dir;
00217 vec3_t origin;
00218
00219 BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
00220 SnapVector( origin );
00221 G_SetOrigin( ent, origin );
00222
00223
00224 dir[0] = dir[1] = 0;
00225 dir[2] = 1;
00226
00227 ent->s.eType = ET_GENERAL;
00228 G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
00229
00230 ent->freeAfterEvent = qtrue;
00231
00232 ent->takedamage = qfalse;
00233
00234 if ( ent->splashDamage ) {
00235 if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent,
00236 ent, ent->splashMethodOfDeath ) )
00237 {
00238 if (ent->parent)
00239 {
00240 g_entities[ent->parent->s.number].client->accuracy_hits++;
00241 }
00242 else if (ent->activator)
00243 {
00244 g_entities[ent->activator->s.number].client->accuracy_hits++;
00245 }
00246 }
00247 }
00248
00249 trap_LinkEntity( ent );
00250 }
00251
00252 void G_RunStuckMissile( gentity_t *ent )
00253 {
00254 if ( ent->takedamage )
00255 {
00256 if ( ent->s.groundEntityNum >= 0 && ent->s.groundEntityNum < ENTITYNUM_WORLD )
00257 {
00258 gentity_t *other = &g_entities[ent->s.groundEntityNum];
00259
00260 if ( (!VectorCompare( vec3_origin, other->s.pos.trDelta ) && other->s.pos.trType != TR_STATIONARY) ||
00261 (!VectorCompare( vec3_origin, other->s.apos.trDelta ) && other->s.apos.trType != TR_STATIONARY) )
00262 {
00263 G_Damage( ent, other, other, NULL, NULL, 99999, 0, MOD_CRUSH );
00264 return;
00265 }
00266 }
00267 }
00268
00269 G_RunThink( ent );
00270 }
00271
00272
00273
00274
00275
00276
00277 void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
00278 vec3_t v, newv;
00279 float dot;
00280
00281 VectorSubtract( impact, start, v );
00282 dot = DotProduct( v, dir );
00283 VectorMA( v, -2*dot, dir, newv );
00284
00285 VectorNormalize(newv);
00286 VectorMA(impact, 8192, newv, endout);
00287 }
00288
00289
00290
00291 gentity_t *CreateMissile( vec3_t org, vec3_t dir, float vel, int life,
00292 gentity_t *owner, qboolean altFire)
00293
00294 {
00295 gentity_t *missile;
00296
00297 missile = G_Spawn();
00298
00299 missile->nextthink = level.time + life;
00300 missile->think = G_FreeEntity;
00301 missile->s.eType = ET_MISSILE;
00302 missile->r.svFlags = SVF_USE_CURRENT_ORIGIN;
00303 missile->parent = owner;
00304 missile->r.ownerNum = owner->s.number;
00305
00306 if (altFire)
00307 {
00308 missile->s.eFlags |= EF_ALT_FIRING;
00309 }
00310
00311 missile->s.pos.trType = TR_LINEAR;
00312 missile->s.pos.trTime = level.time;
00313 missile->target_ent = NULL;
00314
00315 SnapVector(org);
00316 VectorCopy( org, missile->s.pos.trBase );
00317 VectorScale( dir, vel, missile->s.pos.trDelta );
00318 VectorCopy( org, missile->r.currentOrigin);
00319 SnapVector(missile->s.pos.trDelta);
00320
00321 return missile;
00322 }
00323
00324 void G_MissileBounceEffect( gentity_t *ent, vec3_t org, vec3_t dir )
00325 {
00326
00327 switch( ent->s.weapon )
00328 {
00329 case WP_BOWCASTER:
00330 G_PlayEffectID( G_EffectIndex("bowcaster/deflect"), ent->r.currentOrigin, dir );
00331 break;
00332 case WP_BLASTER:
00333 case WP_BRYAR_PISTOL:
00334 G_PlayEffectID( G_EffectIndex("blaster/deflect"), ent->r.currentOrigin, dir );
00335 break;
00336 default:
00337 {
00338 gentity_t *te = G_TempEntity( org, EV_SABER_BLOCK );
00339 VectorCopy(org, te->s.origin);
00340 VectorCopy(dir, te->s.angles);
00341 te->s.eventParm = 0;
00342 te->s.weapon = 0;
00343 te->s.legsAnim = 0;
00344 }
00345 break;
00346 }
00347 }
00348
00349
00350
00351
00352
00353
00354 void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlock );
00355 void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
00356 gentity_t *other;
00357 qboolean hitClient = qfalse;
00358 qboolean isKnockedSaber = qfalse;
00359
00360 other = &g_entities[trace->entityNum];
00361
00362
00363 if ( !other->takedamage &&
00364 (ent->bounceCount > 0 || ent->bounceCount == -5) &&
00365 ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
00366 G_BounceMissile( ent, trace );
00367 G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
00368 return;
00369 }
00370 else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
00371 {
00372 if (ent->bounceCount > 0 || ent->bounceCount == -5)
00373 {
00374 G_BounceMissile( ent, trace );
00375 G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
00376 return;
00377 }
00378
00379 isKnockedSaber = qtrue;
00380 }
00381
00382
00383 if ( (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) )
00384 {
00385 G_BounceMissile( ent, trace );
00386
00387 if ( ent->bounceCount < 1 )
00388 {
00389 ent->flags &= ~FL_BOUNCE_SHRAPNEL;
00390 }
00391 return;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
00408 {
00409 gentity_t *otherOwner = &g_entities[other->r.ownerNum];
00410
00411 if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress &&
00412 otherOwner->client->ps.duelIndex != ent->r.ownerNum)
00413 {
00414 goto killProj;
00415 }
00416 }
00417 else if (!isKnockedSaber)
00418 {
00419 if (other->takedamage && other->client && other->client->ps.duelInProgress &&
00420 other->client->ps.duelIndex != ent->r.ownerNum)
00421 {
00422 goto killProj;
00423 }
00424 }
00425
00426 if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY)
00427 {
00428 if (ent->methodOfDeath != MOD_REPEATER_ALT &&
00429 ent->methodOfDeath != MOD_ROCKET &&
00430 ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
00431 ent->methodOfDeath != MOD_ROCKET_HOMING &&
00432 ent->methodOfDeath != MOD_THERMAL &&
00433 ent->methodOfDeath != MOD_THERMAL_SPLASH &&
00434 ent->methodOfDeath != MOD_TRIP_MINE_SPLASH &&
00435 ent->methodOfDeath != MOD_TIMED_MINE_SPLASH &&
00436 ent->methodOfDeath != MOD_DET_PACK_SPLASH &&
00437 ent->methodOfDeath != MOD_VEHICLE &&
00438 ent->methodOfDeath != MOD_CONC &&
00439 ent->methodOfDeath != MOD_CONC_ALT &&
00440 ent->methodOfDeath != MOD_SABER &&
00441 ent->methodOfDeath != MOD_TURBLAST)
00442 {
00443 vec3_t fwd;
00444
00445 if (trace)
00446 {
00447 VectorCopy(trace->plane.normal, fwd);
00448 }
00449 else
00450 {
00451 AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
00452 }
00453
00454 G_DeflectMissile(other, ent, fwd);
00455 G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
00456 return;
00457 }
00458 }
00459
00460 if ((other->flags & FL_SHIELDED) &&
00461 ent->s.weapon != WP_ROCKET_LAUNCHER &&
00462 ent->s.weapon != WP_THERMAL &&
00463 ent->s.weapon != WP_TRIP_MINE &&
00464 ent->s.weapon != WP_DET_PACK &&
00465 ent->s.weapon != WP_DEMP2 &&
00466 ent->s.weapon != WP_EMPLACED_GUN &&
00467 ent->methodOfDeath != MOD_REPEATER_ALT &&
00468 ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
00469 ent->methodOfDeath != MOD_TURBLAST &&
00470 ent->methodOfDeath != MOD_VEHICLE &&
00471 ent->methodOfDeath != MOD_CONC &&
00472 ent->methodOfDeath != MOD_CONC_ALT &&
00473 !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) )
00474 {
00475 vec3_t fwd;
00476
00477 if (other->client)
00478 {
00479 AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
00480 }
00481 else
00482 {
00483 AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
00484 }
00485
00486 G_DeflectMissile(other, ent, fwd);
00487 G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
00488 return;
00489 }
00490
00491 if (other->takedamage && other->client &&
00492 ent->s.weapon != WP_ROCKET_LAUNCHER &&
00493 ent->s.weapon != WP_THERMAL &&
00494 ent->s.weapon != WP_TRIP_MINE &&
00495 ent->s.weapon != WP_DET_PACK &&
00496 ent->s.weapon != WP_DEMP2 &&
00497 ent->methodOfDeath != MOD_REPEATER_ALT &&
00498 ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
00499 ent->methodOfDeath != MOD_CONC &&
00500 ent->methodOfDeath != MOD_CONC_ALT &&
00501 other->client->ps.saberBlockTime < level.time &&
00502 !isKnockedSaber &&
00503 WP_SaberCanBlock(other, ent->r.currentOrigin, 0, 0, qtrue, 0))
00504 {
00505 vec3_t fwd;
00506 gentity_t *te;
00507 int otherDefLevel = other->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];
00508
00509 te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
00510 VectorCopy(ent->r.currentOrigin, te->s.origin);
00511 VectorCopy(trace->plane.normal, te->s.angles);
00512 te->s.eventParm = 0;
00513 te->s.weapon = 0;
00514 te->s.legsAnim = 0;
00515
00516
00517
00518
00519
00520 if (other->client->ps.velocity[2] > 0 ||
00521 other->client->pers.cmd.forwardmove < 0)
00522 {
00523 otherDefLevel -= 1;
00524 if (otherDefLevel < 0)
00525 {
00526 otherDefLevel = 0;
00527 }
00528 }
00529
00530 AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
00531 if (otherDefLevel == FORCE_LEVEL_1)
00532 {
00533
00534 }
00535 else if (otherDefLevel == FORCE_LEVEL_2)
00536 {
00537 G_DeflectMissile(other, ent, fwd);
00538 }
00539 else
00540 {
00541 G_ReflectMissile(other, ent, fwd);
00542 }
00543 other->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100));
00544
00545
00546 other->client->ps.saberEventFlags |= SEF_DEFLECTED;
00547
00548 if (otherDefLevel == FORCE_LEVEL_3)
00549 {
00550 other->client->ps.saberBlockTime = 0;
00551 }
00552
00553 if (otherDefLevel == FORCE_LEVEL_1)
00554 {
00555 goto killProj;
00556 }
00557 return;
00558 }
00559 else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
00560 {
00561 gentity_t *otherOwner = &g_entities[other->r.ownerNum];
00562
00563 if (otherOwner->takedamage && otherOwner->client &&
00564 ent->s.weapon != WP_ROCKET_LAUNCHER &&
00565 ent->s.weapon != WP_THERMAL &&
00566 ent->s.weapon != WP_TRIP_MINE &&
00567 ent->s.weapon != WP_DET_PACK &&
00568 ent->s.weapon != WP_DEMP2 &&
00569 ent->methodOfDeath != MOD_REPEATER_ALT &&
00570 ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
00571 ent->methodOfDeath != MOD_CONC &&
00572 ent->methodOfDeath != MOD_CONC_ALT
00573 )
00574 {
00575 vec3_t fwd;
00576 gentity_t *te;
00577 int otherDefLevel = otherOwner->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];
00578
00579
00580
00581 if (otherOwner->client && otherOwner->client->ps.weaponTime <= 0)
00582 {
00583 WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue);
00584 }
00585
00586 te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
00587 VectorCopy(ent->r.currentOrigin, te->s.origin);
00588 VectorCopy(trace->plane.normal, te->s.angles);
00589 te->s.eventParm = 0;
00590 te->s.weapon = 0;
00591 te->s.legsAnim = 0;
00592
00593
00594
00595
00596 if (otherOwner->client->ps.velocity[2] > 0 ||
00597 otherOwner->client->pers.cmd.forwardmove < 0)
00598 {
00599 otherDefLevel -= 1;
00600 if (otherDefLevel < 0)
00601 {
00602 otherDefLevel = 0;
00603 }
00604 }
00605
00606 AngleVectors(otherOwner->client->ps.viewangles, fwd, NULL, NULL);
00607
00608 if (otherDefLevel == FORCE_LEVEL_1)
00609 {
00610
00611 }
00612 else if (otherDefLevel == FORCE_LEVEL_2)
00613 {
00614 G_DeflectMissile(otherOwner, ent, fwd);
00615 }
00616 else
00617 {
00618 G_ReflectMissile(otherOwner, ent, fwd);
00619 }
00620 otherOwner->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100));
00621
00622
00623 otherOwner->client->ps.saberEventFlags |= SEF_DEFLECTED;
00624
00625 if (otherDefLevel == FORCE_LEVEL_3)
00626 {
00627 otherOwner->client->ps.saberBlockTime = 0;
00628 }
00629
00630 if (otherDefLevel == FORCE_LEVEL_1)
00631 {
00632 goto killProj;
00633 }
00634 return;
00635 }
00636 }
00637
00638
00639 if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) )
00640 {
00641 laserTrapStick( ent, trace->endpos, trace->plane.normal );
00642 G_AddEvent( ent, EV_MISSILE_STICK, 0 );
00643 return;
00644 }
00645
00646
00647 if (other->takedamage && !isKnockedSaber) {
00648
00649 if ( ent->damage ) {
00650 vec3_t velocity;
00651 qboolean didDmg = qfalse;
00652
00653 if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
00654 g_entities[ent->r.ownerNum].client->accuracy_hits++;
00655 hitClient = qtrue;
00656 }
00657 BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
00658 if ( VectorLength( velocity ) == 0 ) {
00659 velocity[2] = 1;
00660 }
00661
00662 if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE ||
00663 ent->s.weapon == WP_ROCKET_LAUNCHER)
00664 {
00665 if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING))
00666 {
00667 ent->think(ent);
00668 }
00669 else
00670 {
00671 G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
00672 ent->r.currentOrigin, ent->damage,
00673 DAMAGE_HALF_ABSORB, ent->methodOfDeath);
00674 didDmg = qtrue;
00675 }
00676 }
00677 else
00678 {
00679 G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
00680 ent->r.currentOrigin, ent->damage,
00681 0, ent->methodOfDeath);
00682 didDmg = qtrue;
00683 }
00684
00685 if (didDmg && other && other->client)
00686 {
00687 class_t npc_class = other->client->NPC_class;
00688
00689
00690 if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
00691 npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
00692 npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 ||
00693 npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
00694 {
00695
00696 if ( other->client->ps.electrifyTime < level.time + 100 )
00697 {
00698
00699 other->client->ps.electrifyTime = level.time + 450;
00700 }
00701
00702 }
00703 }
00704 }
00705
00706 if ( ent->s.weapon == WP_DEMP2 )
00707 {
00708 if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE )
00709 {
00710 if ( other->m_pVehicle
00711 && other->m_pVehicle->m_pVehicleInfo
00712 && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER
00713 ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )
00714 && !FighterIsLanded( other->m_pVehicle , &other->client->ps )
00715 && !(other->spawnflags&2) )
00716 {
00717 if ( other->client->ps.electrifyTime > level.time )
00718 {
00719
00720 other->client->ps.electrifyTime += Q_irand(200,500);
00721 if ( other->client->ps.electrifyTime > level.time + 4000 )
00722 {
00723 other->client->ps.electrifyTime = level.time + 4000;
00724 }
00725 }
00726 else
00727 {
00728
00729 other->client->ps.electrifyTime = level.time + Q_irand(200,500);
00730 }
00731 }
00732 }
00733 else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] )
00734 {
00735 Jedi_Decloak( other );
00736 if ( ent->methodOfDeath == MOD_DEMP2_ALT )
00737 {
00738
00739 other->client->cloakToggleTime = Q3_INFINITE;
00740 }
00741 else
00742 {
00743 other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 );
00744 }
00745 }
00746 }
00747 }
00748 killProj:
00749
00750
00751
00752 if ( other->takedamage && other->client && !isKnockedSaber ) {
00753 G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
00754 ent->s.otherEntityNum = other->s.number;
00755 } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
00756 G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
00757 } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) {
00758 G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
00759 }
00760
00761 if (!isKnockedSaber)
00762 {
00763 ent->freeAfterEvent = qtrue;
00764
00765
00766 ent->s.eType = ET_GENERAL;
00767 }
00768
00769 SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
00770
00771 G_SetOrigin( ent, trace->endpos );
00772
00773 ent->takedamage = qfalse;
00774
00775 if ( ent->splashDamage ) {
00776 if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
00777 other, ent, ent->splashMethodOfDeath ) ) {
00778 if( !hitClient
00779 && g_entities[ent->r.ownerNum].client ) {
00780 g_entities[ent->r.ownerNum].client->accuracy_hits++;
00781 }
00782 }
00783 }
00784
00785 if (ent->s.weapon == G2_MODEL_PART)
00786 {
00787 ent->freeAfterEvent = qfalse;
00788 }
00789
00790 trap_LinkEntity( ent );
00791 }
00792
00793
00794
00795
00796
00797
00798 void G_RunMissile( gentity_t *ent ) {
00799 vec3_t origin, groundSpot;
00800 trace_t tr;
00801 int passent;
00802 qboolean isKnockedSaber = qfalse;
00803
00804 if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
00805 {
00806 isKnockedSaber = qtrue;
00807 ent->s.pos.trType = TR_GRAVITY;
00808 }
00809
00810
00811 BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
00812
00813
00814 if ( ent->target_ent ) {
00815 passent = ent->target_ent->s.number;
00816 }
00817 else {
00818
00819 if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
00820 && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
00821 {
00822
00823 passent = ent->s.number;
00824 }
00825 else
00826 {
00827 passent = ent->r.ownerNum;
00828 }
00829 }
00830
00831 if (d_projectileGhoul2Collision.integer)
00832 {
00833 trap_G2Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );
00834
00835 if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
00836 {
00837 gentity_t *g2Hit = &g_entities[tr.entityNum];
00838
00839 if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
00840 {
00841 g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
00842 g2Hit->client->g2LastSurfaceTime = level.time;
00843 }
00844
00845 if (g2Hit->ghoul2)
00846 {
00847 tr.surfaceFlags = 0;
00848 }
00849 }
00850 }
00851 else
00852 {
00853 trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
00854 }
00855
00856 if ( tr.startsolid || tr.allsolid ) {
00857
00858 trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
00859 tr.fraction = 0;
00860 }
00861 else {
00862 VectorCopy( tr.endpos, ent->r.currentOrigin );
00863 }
00864
00865 if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
00866 {
00867 VectorCopy( origin, ent->r.currentOrigin );
00868 trap_LinkEntity( ent );
00869 goto passthrough;
00870 }
00871
00872 trap_LinkEntity( ent );
00873
00874 if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
00875 {
00876 vec3_t lowerOrg;
00877 trace_t trG;
00878
00879 VectorCopy(ent->r.currentOrigin, lowerOrg);
00880 lowerOrg[2] -= 1;
00881 trap_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask );
00882
00883 VectorCopy(trG.endpos, groundSpot);
00884
00885 if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
00886 {
00887 ent->s.groundEntityNum = trG.entityNum;
00888 }
00889 else
00890 {
00891 ent->s.groundEntityNum = ENTITYNUM_NONE;
00892 }
00893 }
00894
00895 if ( tr.fraction != 1) {
00896
00897 if ( tr.surfaceFlags & SURF_NOIMPACT ) {
00898
00899 if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
00900 ent->parent->client->hook = NULL;
00901 }
00902
00903 if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
00904 {
00905 G_RunThink( ent );
00906 return;
00907 }
00908 else if (ent->s.weapon != G2_MODEL_PART)
00909 {
00910 G_FreeEntity( ent );
00911 return;
00912 }
00913 }
00914
00915 #if 0 //will get stomped with missile impact event...
00916 if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
00917 (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
00918 {
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 G_AddEvent(ent, EV_GHOUL2_MARK, 0);
00937
00938
00939 VectorCopy(ent->r.currentOrigin, ent->s.origin);
00940 BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );
00941
00942
00943 ent->s.otherEntityNum = tr.entityNum;
00944
00945 if (VectorCompare(ent->s.origin, ent->s.origin2))
00946 {
00947 ent->s.origin2[2] += 2.0f;
00948 }
00949 }
00950 #else
00951 if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
00952 (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
00953 {
00954
00955 VectorCopy(ent->r.currentOrigin, ent->s.origin);
00956 BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );
00957
00958 if (VectorCompare(ent->s.origin, ent->s.origin2))
00959 {
00960 ent->s.origin2[2] += 2.0f;
00961 }
00962 }
00963 #endif
00964
00965 G_MissileImpact( ent, &tr );
00966
00967 if (tr.entityNum == ent->s.otherEntityNum)
00968 {
00969 ent->s.trickedentindex = 1;
00970 }
00971
00972 if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
00973 {
00974 return;
00975 }
00976 }
00977
00978 passthrough:
00979 if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
00980 {
00981 G_RunStuckMissile( ent );
00982 return;
00983 }
00984
00985 if (ent->s.weapon == G2_MODEL_PART)
00986 {
00987 if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
00988 {
0098