00001
00002
00003
00004
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
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
00024
00025 #define BLASTER_SPREAD 1.6f//1.2f
00026 #define BLASTER_VELOCITY 2300
00027 #define BLASTER_DAMAGE 20
00028
00029
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
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
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
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
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
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
00098
00099
00100
00101
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
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
00116
00117 #define STUN_BATON_DAMAGE 20
00118 #define STUN_BATON_ALT_DAMAGE 20
00119 #define STUN_BATON_RANGE 8
00120
00121
00122
00123 #define MELEE_SWING1_DAMAGE 10
00124 #define MELEE_SWING2_DAMAGE 12
00125 #define MELEE_RANGE 8
00126
00127
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
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
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
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
00222
00223
00224
00225
00226
00227
00228
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;
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
00290 missile->bounceCount = 8;
00291 }
00292
00293
00294
00295
00296
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
00323 missile->bounceCount = 8;
00324 }
00325
00326
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
00345 missile->bounceCount = 8;
00346 }
00347
00348
00349
00350
00351
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 {
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
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;
00388 gentity_t *missile;
00389
00390 missile = CreateMissile( start, dir, velocity, 10000, ent, qfalse );
00391
00392
00393 missile->s.otherEntityNum2 = ent->genericValue14;
00394
00395 missile->s.emplacedOwner = ent->genericValue15;
00396
00397 missile->classname = "turbo_proj";
00398 missile->s.weapon = WP_TURRET;
00399
00400 missile->damage = ent->damage;
00401 missile->splashDamage = ent->splashDamage;
00402 missile->splashRadius = ent->splashRadius;
00403 missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00404 missile->methodOfDeath = MOD_TURBLAST;
00405 missile->splashMethodOfDeath = MOD_TURBLAST;
00406 missile->clipmask = MASK_SHOT;
00407
00408
00409 missile->bounceCount = 8;
00410
00411
00412 missile->s.owner = ent->s.number;
00413
00414
00415 missile->think = G_FreeEntity;
00416 missile->nextthink = level.time + 5000;
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;
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
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
00459 angs[PITCH] += crandom() * BLASTER_SPREAD;
00460 angs[YAW] += crandom() * BLASTER_SPREAD;
00461 }
00462
00463 AngleVectors( angs, dir, NULL, NULL );
00464
00465
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
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));
00498
00499 VectorCopy( ent->client->ps.origin, start );
00500 start[2] += ent->client->ps.viewheight;
00501
00502 VectorMA( start, shotRange, forward, end );
00503
00504 ignore = ent->s.number;
00505 traces = 0;
00506 while ( traces < 10 )
00507 {
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 {
00521 if (traceEnt->inuse && traceEnt->client && traceEnt->ghoul2)
00522 {
00523 traceEnt->client->g2LastSurfaceHit = tr.surfaceFlags;
00524 traceEnt->client->g2LastSurfaceTime = level.time;
00525 }
00526
00527 if (traceEnt->ghoul2)
00528 {
00529 tr.surfaceFlags = 0;
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 {
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 {
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;
00568 te->s.legsAnim = 0;
00569
00570 return;
00571 }
00572 }
00573 else if ( (traceEnt->flags&FL_SHIELDED) )
00574 {
00575 return;
00576 }
00577
00578 break;
00579 }
00580
00581 if ( tr.surfaceFlags & SURF_NOIMPACT )
00582 {
00583 render_impact = qfalse;
00584 }
00585
00586
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
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 {
00627 return qtrue;
00628 }
00629
00630 if (ent->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
00631 {
00632 return qtrue;
00633 }
00634
00635
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 );
00658
00659 if (ent->client)
00660 {
00661 VectorCopy( ent->client->ps.origin, start );
00662 start[2] += ent->client->ps.viewheight;
00663
00664 count = ( level.time - ent->client->ps.weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT;
00665 if ( g_gametype.integer == GT_SIEGE )
00666 {
00667
00668 maxCount = 200;
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
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 {
00722 if (traceEnt->inuse && traceEnt->client && traceEnt->ghoul2)
00723 {
00724 traceEnt->client->g2LastSurfaceHit = tr.surfaceFlags;
00725 traceEnt->client->g2LastSurfaceTime = level.time;
00726 }
00727
00728 if (traceEnt->ghoul2)
00729 {
00730 tr.surfaceFlags = 0;
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 {
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;
00773 te->s.legsAnim = 0;
00774
00775 return;
00776 }
00777 }
00778
00779
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
00786 if ( render_impact )
00787 {
00788 if ( traceEnt->takedamage && traceEnt->client )
00789 {
00790 tent->s.otherEntityNum = traceEnt->s.number;
00791
00792
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
00823 tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_MISS );
00824 tent->s.eventParm = DirToByte( tr.plane.normal );
00825 }
00826 break;
00827 }
00828
00829 if ( (traceEnt->flags&FL_SHIELDED) )
00830 {
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 {
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
00875 {
00876 break;
00877 }
00878
00879
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 {
00893 altFire = qfalse;
00894 }
00895
00896 if (ent && ent->s.eType == ET_NPC && !ent->client)
00897 {
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
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
00973 count--;
00974 }
00975
00976
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
01001 vel = BOWCASTER_VELOCITY * ( crandom() * BOWCASTER_VEL_RANGE + 1.0f );
01002
01003 vectoangles( forward, angs );
01004
01005
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
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
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
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;
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 )
01095 {
01096 missile->splashRadius = REPEATER_ALT_SPLASH_RAD_SIEGE;
01097 }
01098 else
01099 {
01100 missile->splashRadius = REPEATER_ALT_SPLASH_RADIUS;
01101 }
01102
01103
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
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
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
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;
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_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;
01188
01189 radius = frac * 200.0f;
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
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
01242 v[2] *= 0.5f;
01243
01244 dist = VectorLength( v );
01245
01246 if ( dist >= radius )
01247 {
01248
01249 continue;
01250 }
01251
01252 if (dist+(16*ent->