00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "g_local.h"
00027
00028 static float s_quadFactor;
00029 static vec3_t forward, right, up;
00030 static vec3_t muzzle;
00031
00032 #define NUM_NAILSHOTS 15
00033
00034
00035
00036
00037
00038
00039 void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
00040 vec3_t v, newv;
00041 float dot;
00042
00043 VectorSubtract( impact, start, v );
00044 dot = DotProduct( v, dir );
00045 VectorMA( v, -2*dot, dir, newv );
00046
00047 VectorNormalize(newv);
00048 VectorMA(impact, 8192, newv, endout);
00049 }
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 void Weapon_Gauntlet( gentity_t *ent ) {
00061
00062 }
00063
00064
00065
00066
00067
00068
00069 qboolean CheckGauntletAttack( gentity_t *ent ) {
00070 trace_t tr;
00071 vec3_t end;
00072 gentity_t *tent;
00073 gentity_t *traceEnt;
00074 int damage;
00075
00076
00077 AngleVectors (ent->client->ps.viewangles, forward, right, up);
00078
00079 CalcMuzzlePoint ( ent, forward, right, up, muzzle );
00080
00081 VectorMA (muzzle, 32, forward, end);
00082
00083 trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
00084 if ( tr.surfaceFlags & SURF_NOIMPACT ) {
00085 return qfalse;
00086 }
00087
00088 traceEnt = &g_entities[ tr.entityNum ];
00089
00090
00091 if ( traceEnt->takedamage && traceEnt->client ) {
00092 tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
00093 tent->s.otherEntityNum = traceEnt->s.number;
00094 tent->s.eventParm = DirToByte( tr.plane.normal );
00095 tent->s.weapon = ent->s.weapon;
00096 }
00097
00098 if ( !traceEnt->takedamage) {
00099 return qfalse;
00100 }
00101
00102 if (ent->client->ps.powerups[PW_QUAD] ) {
00103 G_AddEvent( ent, EV_POWERUP_QUAD, 0 );
00104 s_quadFactor = g_quadfactor.value;
00105 } else {
00106 s_quadFactor = 1;
00107 }
00108 #ifdef MISSIONPACK
00109 if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
00110 s_quadFactor *= 2;
00111 }
00112 #endif
00113
00114 damage = 50 * s_quadFactor;
00115 G_Damage( traceEnt, ent, ent, forward, tr.endpos,
00116 damage, 0, MOD_GAUNTLET );
00117
00118 return qtrue;
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 void SnapVectorTowards( vec3_t v, vec3_t to ) {
00141 int i;
00142
00143 for ( i = 0 ; i < 3 ; i++ ) {
00144 if ( to[i] <= v[i] ) {
00145 v[i] = (int)v[i];
00146 } else {
00147 v[i] = (int)v[i] + 1;
00148 }
00149 }
00150 }
00151
00152 #ifdef MISSIONPACK
00153 #define CHAINGUN_SPREAD 600
00154 #endif
00155 #define MACHINEGUN_SPREAD 200
00156 #define MACHINEGUN_DAMAGE 7
00157 #define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
00158
00159 void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
00160 trace_t tr;
00161 vec3_t end;
00162 #ifdef MISSIONPACK
00163 vec3_t impactpoint, bouncedir;
00164 #endif
00165 float r;
00166 float u;
00167 gentity_t *tent;
00168 gentity_t *traceEnt;
00169 int i, passent;
00170
00171 damage *= s_quadFactor;
00172
00173 r = random() * M_PI * 2.0f;
00174 u = sin(r) * crandom() * spread * 16;
00175 r = cos(r) * crandom() * spread * 16;
00176 VectorMA (muzzle, 8192*16, forward, end);
00177 VectorMA (end, r, right, end);
00178 VectorMA (end, u, up, end);
00179
00180 passent = ent->s.number;
00181 for (i = 0; i < 10; i++) {
00182
00183 trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
00184 if ( tr.surfaceFlags & SURF_NOIMPACT ) {
00185 return;
00186 }
00187
00188 traceEnt = &g_entities[ tr.entityNum ];
00189
00190
00191 SnapVectorTowards( tr.endpos, muzzle );
00192
00193
00194 if ( traceEnt->takedamage && traceEnt->client ) {
00195 tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
00196 tent->s.eventParm = traceEnt->s.number;
00197 if( LogAccuracyHit( traceEnt, ent ) ) {
00198 ent->client->accuracy_hits++;
00199 }
00200 } else {
00201 tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
00202 tent->s.eventParm = DirToByte( tr.plane.normal );
00203 }
00204 tent->s.otherEntityNum = ent->s.number;
00205
00206 if ( traceEnt->takedamage) {
00207 #ifdef MISSIONPACK
00208 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
00209 if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
00210 G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
00211 VectorCopy( impactpoint, muzzle );
00212
00213 passent = ENTITYNUM_NONE;
00214 }
00215 else {
00216 VectorCopy( tr.endpos, muzzle );
00217 passent = traceEnt->s.number;
00218 }
00219 continue;
00220 }
00221 else {
00222 #endif
00223 G_Damage( traceEnt, ent, ent, forward, tr.endpos,
00224 damage, 0, MOD_MACHINEGUN);
00225 #ifdef MISSIONPACK
00226 }
00227 #endif
00228 }
00229 break;
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 void BFG_Fire ( gentity_t *ent ) {
00243 gentity_t *m;
00244
00245 m = fire_bfg (ent, muzzle, forward);
00246 m->damage *= s_quadFactor;
00247 m->splashDamage *= s_quadFactor;
00248
00249
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 #define DEFAULT_SHOTGUN_DAMAGE 10
00264
00265 qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
00266 trace_t tr;
00267 int damage, i, passent;
00268 gentity_t *traceEnt;
00269 #ifdef MISSIONPACK
00270 vec3_t impactpoint, bouncedir;
00271 #endif
00272 vec3_t tr_start, tr_end;
00273
00274 passent = ent->s.number;
00275 VectorCopy( start, tr_start );
00276 VectorCopy( end, tr_end );
00277 for (i = 0; i < 10; i++) {
00278 trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
00279 traceEnt = &g_entities[ tr.entityNum ];
00280
00281
00282 if ( tr.surfaceFlags & SURF_NOIMPACT ) {
00283 return qfalse;
00284 }
00285
00286 if ( traceEnt->takedamage) {
00287 damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;
00288 #ifdef MISSIONPACK
00289 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
00290 if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
00291 G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
00292 VectorCopy( impactpoint, tr_start );
00293
00294 passent = ENTITYNUM_NONE;
00295 }
00296 else {
00297 VectorCopy( tr.endpos, tr_start );
00298 passent = traceEnt->s.number;
00299 }
00300 continue;
00301 }
00302 else {
00303 G_Damage( traceEnt, ent, ent, forward, tr.endpos,
00304 damage, 0, MOD_SHOTGUN);
00305 if( LogAccuracyHit( traceEnt, ent ) ) {
00306 return qtrue;
00307 }
00308 }
00309 #else
00310 G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_SHOTGUN);
00311 if( LogAccuracyHit( traceEnt, ent ) ) {
00312 return qtrue;
00313 }
00314 #endif
00315 }
00316 return qfalse;
00317 }
00318 return qfalse;
00319 }
00320
00321
00322 void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
00323 int i;
00324 float r, u;
00325 vec3_t end;
00326 vec3_t forward, right, up;
00327 int oldScore;
00328 qboolean hitClient = qfalse;
00329
00330
00331
00332 VectorNormalize2( origin2, forward );
00333 PerpendicularVector( right, forward );
00334 CrossProduct( forward, right, up );
00335
00336 oldScore = ent->client->ps.persistant[PERS_SCORE];
00337
00338
00339 for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
00340 r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
00341 u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
00342 VectorMA( origin, 8192 * 16, forward, end);
00343 VectorMA (end, r, right, end);
00344 VectorMA (end, u, up, end);
00345 if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
00346 hitClient = qtrue;
00347 ent->client->accuracy_hits++;
00348 }
00349 }
00350 }
00351
00352
00353 void weapon_supershotgun_fire (gentity_t *ent) {
00354 gentity_t *tent;
00355
00356
00357 tent = G_TempEntity( muzzle, EV_SHOTGUN );
00358 VectorScale( forward, 4096, tent->s.origin2 );
00359 SnapVector( tent->s.origin2 );
00360 tent->s.eventParm = rand() & 255;
00361 tent->s.otherEntityNum = ent->s.number;
00362
00363 ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 void weapon_grenadelauncher_fire (gentity_t *ent) {
00376 gentity_t *m;
00377
00378
00379 forward[2] += 0.2f;
00380 VectorNormalize( forward );
00381
00382 m = fire_grenade (ent, muzzle, forward);
00383 m->damage *= s_quadFactor;
00384 m->splashDamage *= s_quadFactor;
00385
00386
00387 }
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 void Weapon_RocketLauncher_Fire (gentity_t *ent) {
00398 gentity_t *m;
00399
00400 m = fire_rocket (ent, muzzle, forward);
00401 m->damage *= s_quadFactor;
00402 m->splashDamage *= s_quadFactor;
00403
00404
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 void Weapon_Plasmagun_Fire (gentity_t *ent) {
00417 gentity_t *m;
00418
00419 m = fire_plasma (ent, muzzle, forward);
00420 m->damage *= s_quadFactor;
00421 m->splashDamage *= s_quadFactor;
00422
00423
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 #define MAX_RAIL_HITS 4
00441 void weapon_railgun_fire (gentity_t *ent) {
00442 vec3_t end;
00443 #ifdef MISSIONPACK
00444 vec3_t impactpoint, bouncedir;
00445 #endif
00446 trace_t trace;
00447 gentity_t *tent;
00448 gentity_t *traceEnt;
00449 int damage;
00450 int i;
00451 int hits;
00452 int unlinked;
00453 int passent;
00454 gentity_t *unlinkedEntities[MAX_RAIL_HITS];
00455
00456 damage = 100 * s_quadFactor;
00457
00458 VectorMA (muzzle, 8192, forward, end);
00459
00460
00461 unlinked = 0;
00462 hits = 0;
00463 passent = ent->s.number;
00464 do {
00465 trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
00466 if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
00467 break;
00468 }
00469 traceEnt = &g_entities[ trace.entityNum ];
00470 if ( traceEnt->takedamage ) {
00471 #ifdef MISSIONPACK
00472 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
00473 if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
00474 G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
00475
00476 SnapVectorTowards( trace.endpos, muzzle );
00477
00478 tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
00479
00480 tent->s.clientNum = ent->s.clientNum;
00481 VectorCopy( muzzle, tent->s.origin2 );
00482
00483 VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
00484 VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
00485 tent->s.eventParm = 255;
00486
00487 VectorCopy( impactpoint, muzzle );
00488
00489 passent = ENTITYNUM_NONE;
00490 }
00491 }
00492 else {
00493 if( LogAccuracyHit( traceEnt, ent ) ) {
00494 hits++;
00495 }
00496 G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
00497 }
00498 #else
00499 if( LogAccuracyHit( traceEnt, ent ) ) {
00500 hits++;
00501 }
00502 G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
00503 #endif
00504 }
00505 if ( trace.contents & CONTENTS_SOLID ) {
00506 break;
00507 }
00508
00509 trap_UnlinkEntity( traceEnt );
00510 unlinkedEntities[unlinked] = traceEnt;
00511 unlinked++;
00512 } while ( unlinked < MAX_RAIL_HITS );
00513
00514
00515 for ( i = 0 ; i < unlinked ; i++ ) {
00516 trap_LinkEntity( unlinkedEntities[i] );
00517 }
00518
00519
00520
00521
00522 SnapVectorTowards( trace.endpos, muzzle );
00523
00524
00525 tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
00526
00527
00528 tent->s.clientNum = ent->s.clientNum;
00529
00530 VectorCopy( muzzle, tent->s.origin2 );
00531
00532 VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
00533 VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
00534
00535
00536 if ( trace.surfaceFlags & SURF_NOIMPACT ) {
00537 tent->s.eventParm = 255;
00538 } else {
00539 tent->s.eventParm = DirToByte( trace.plane.normal );
00540 }
00541 tent->s.clientNum = ent->s.clientNum;
00542
00543
00544 if ( hits == 0 ) {
00545
00546 ent->client->accurateCount = 0;
00547 } else {
00548
00549 ent->client->accurateCount += hits;
00550 if ( ent->client->accurateCount >= 2 ) {
00551 ent->client->accurateCount -= 2;
00552 ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
00553
00554 ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00555 ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
00556 ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00557 }
00558 ent->client->accuracy_hits++;
00559 }
00560
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 void Weapon_GrapplingHook_Fire (gentity_t *ent)
00573 {
00574 if (!ent->client->fireHeld && !ent->client->hook)
00575 fire_grapple (ent, muzzle, forward);
00576
00577 ent->client->fireHeld = qtrue;
00578 }
00579
00580 void Weapon_HookFree (gentity_t *ent)
00581 {
00582 ent->parent->client->hook = NULL;
00583 ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
00584 G_FreeEntity( ent );
00585 }
00586
00587 void Weapon_HookThink (gentity_t *ent)
00588 {
00589 if (ent->enemy) {
00590 vec3_t v, oldorigin;
00591
00592 VectorCopy(ent->r.currentOrigin, oldorigin);
00593 v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
00594 v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
00595 v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
00596 SnapVectorTowards( v, oldorigin );
00597
00598 G_SetOrigin( ent, v );
00599 }
00600
00601 VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 void Weapon_LightningFire( gentity_t *ent ) {
00613 trace_t tr;
00614 vec3_t end;
00615 #ifdef MISSIONPACK
00616 vec3_t impactpoint, bouncedir;
00617 #endif
00618 gentity_t *traceEnt, *tent;
00619 int damage, i, passent;
00620
00621 damage = 8 * s_quadFactor;
00622
00623 passent = ent->s.number;
00624 for (i = 0; i < 10; i++) {
00625 VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
00626
00627 trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
00628
00629 #ifdef MISSIONPACK
00630
00631 if (i) {
00632
00633
00634
00635 tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
00636 VectorCopy( tr.endpos, end );
00637 SnapVector( end );
00638 VectorCopy( end, tent->s.origin2 );
00639 }
00640 #endif
00641 if ( tr.entityNum == ENTITYNUM_NONE ) {
00642 return;
00643 }
00644
00645 traceEnt = &g_entities[ tr.entityNum ];
00646
00647 if ( traceEnt->takedamage) {
00648 #ifdef MISSIONPACK
00649 if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
00650 if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
00651 G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
00652 VectorCopy( impactpoint, muzzle );
00653 VectorSubtract( end, impactpoint, forward );
00654 VectorNormalize(forward);
00655
00656 passent = ENTITYNUM_NONE;
00657 }
00658 else {
00659 VectorCopy( tr.endpos, muzzle );
00660 passent = traceEnt->s.number;
00661 }
00662 continue;
00663 }
00664 else {
00665 G_Damage( traceEnt, ent, ent, forward, tr.endpos,
00666 damage, 0, MOD_LIGHTNING);
00667 }
00668 #else
00669 G_Damage( traceEnt, ent, ent, forward, tr.endpos,
00670 damage, 0, MOD_LIGHTNING);
00671 #endif
00672 }
00673
00674 if ( traceEnt->takedamage && traceEnt->client ) {
00675 tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
00676 tent->s.otherEntityNum = traceEnt->s.number;
00677 tent->s.eventParm = DirToByte( tr.plane.normal );
00678 tent->s.weapon = ent->s.weapon;
00679 if( LogAccuracyHit( traceEnt, ent ) ) {
00680 ent->client->accuracy_hits++;
00681 }
00682 } else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
00683 tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
00684 tent->s.eventParm = DirToByte( tr.plane.normal );
00685 }
00686
00687 break;
00688 }
00689 }
00690
00691 #ifdef MISSIONPACK
00692
00693
00694
00695
00696
00697
00698
00699
00700 void Weapon_Nailgun_Fire (gentity_t *ent) {
00701 gentity_t *m;
00702 int count;
00703
00704 for( count = 0; count < NUM_NAILSHOTS; count++ ) {
00705 m = fire_nail (ent, muzzle, forward, right, up );
00706 m->damage *= s_quadFactor;
00707 m->splashDamage *= s_quadFactor;
00708 }
00709
00710
00711 }
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722 void weapon_proxlauncher_fire (gentity_t *ent) {
00723 gentity_t *m;
00724
00725
00726 forward[2] += 0.2f;
00727 VectorNormalize( forward );
00728
00729 m = fire_prox (ent, muzzle, forward);
00730 m->damage *= s_quadFactor;
00731 m->splashDamage *= s_quadFactor;
00732
00733
00734 }
00735
00736 #endif
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {
00747 if( !target->takedamage ) {
00748 return qfalse;
00749 }
00750
00751 if ( target == attacker ) {
00752 return qfalse;
00753 }
00754
00755 if( !target->client ) {
00756 return qfalse;
00757 }
00758
00759 if( !attacker->client ) {
00760 return qfalse;
00761 }
00762
00763 if( target->client->ps.stats[STAT_HEALTH] <= 0 ) {
00764 return qfalse;
00765 }
00766
00767 if ( OnSameTeam( target, attacker ) ) {
00768 return qfalse;
00769 }
00770
00771 return qtrue;
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782 void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
00783 VectorCopy( ent->s.pos.trBase, muzzlePoint );
00784 muzzlePoint[2] += ent->client->ps.viewheight;
00785 VectorMA( muzzlePoint, 14, forward, muzzlePoint );
00786
00787 SnapVector( muzzlePoint );
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797 void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
00798 VectorCopy( ent->s.pos.trBase, muzzlePoint );
00799 muzzlePoint[2] += ent->client->ps.viewheight;
00800 VectorMA( muzzlePoint, 14, forward, muzzlePoint );
00801
00802 SnapVector( muzzlePoint );
00803 }
00804
00805
00806
00807
00808
00809
00810
00811
00812 void FireWeapon( gentity_t *ent ) {
00813 if (ent->client->ps.powerups[PW_QUAD] ) {
00814 s_quadFactor = g_quadfactor.value;
00815 } else {
00816 s_quadFactor = 1;
00817 }
00818 #ifdef MISSIONPACK
00819 if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
00820 s_quadFactor *= 2;
00821 }
00822 #endif
00823
00824
00825 if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
00826 #ifdef MISSIONPACK
00827 if( ent->s.weapon == WP_NAILGUN ) {
00828 ent->client->accuracy_shots += NUM_NAILSHOTS;
00829 } else {
00830 ent->client->accuracy_shots++;
00831 }
00832 #else
00833 ent->client->accuracy_shots++;
00834 #endif
00835 }
00836
00837
00838 AngleVectors (ent->client->ps.viewangles, forward, right, up);
00839
00840 CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
00841
00842
00843 switch( ent->s.weapon ) {
00844 case WP_GAUNTLET:
00845 Weapon_Gauntlet( ent );
00846 break;
00847 case WP_LIGHTNING:
00848 Weapon_LightningFire( ent );
00849 break;
00850 case WP_SHOTGUN:
00851 weapon_supershotgun_fire( ent );
00852 break;
00853 case WP_MACHINEGUN:
00854 if ( g_gametype.integer != GT_TEAM ) {
00855 Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );
00856 } else {
00857 Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
00858 }
00859 break;
00860 case WP_GRENADE_LAUNCHER:
00861 weapon_grenadelauncher_fire( ent );
00862 break;
00863 case WP_ROCKET_LAUNCHER:
00864 Weapon_RocketLauncher_Fire( ent );
00865 break;
00866 case WP_PLASMAGUN:
00867 Weapon_Plasmagun_Fire( ent );
00868 break;
00869 case WP_RAILGUN:
00870 weapon_railgun_fire( ent );
00871 break;
00872 case WP_BFG:
00873 BFG_Fire( ent );
00874 break;
00875 case WP_GRAPPLING_HOOK:
00876 Weapon_GrapplingHook_Fire( ent );
00877 break;
00878 #ifdef MISSIONPACK
00879 case WP_NAILGUN:
00880 Weapon_Nailgun_Fire( ent );
00881 break;
00882 case WP_PROX_LAUNCHER:
00883 weapon_proxlauncher_fire( ent );
00884 break;
00885 case WP_CHAINGUN:
00886 Bullet_Fire( ent, CHAINGUN_SPREAD, MACHINEGUN_DAMAGE );
00887 break;
00888 #endif
00889 default:
00890
00891 break;
00892 }
00893 }
00894
00895
00896 #ifdef MISSIONPACK
00897
00898
00899
00900
00901
00902
00903 static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
00904 float dist;
00905 gentity_t *ent;
00906 int entityList[MAX_GENTITIES];
00907 int numListedEntities;
00908 vec3_t mins, maxs;
00909 vec3_t v;
00910 vec3_t dir;
00911 int i, e;
00912
00913 if ( radius < 1 ) {
00914 radius = 1;
00915 }
00916
00917 for ( i = 0 ; i < 3 ; i++ ) {
00918 mins[i] = origin[i] - radius;
00919 maxs[i] = origin[i] + radius;
00920 }
00921
00922 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
00923
00924 for ( e = 0 ; e < numListedEntities ; e++ ) {
00925 ent = &g_entities[entityList[ e ]];
00926
00927 if (!ent->takedamage) {
00928 continue;
00929 }
00930
00931
00932 if( ent->kamikazeTime > level.time ) {
00933 continue;
00934 }
00935
00936
00937 for ( i = 0 ; i < 3 ; i++ ) {
00938 if ( origin[i] < ent->r.absmin[i] ) {
00939 v[i] = ent->r.absmin[i] - origin[i];
00940 } else if ( origin[i] > ent->r.absmax[i] ) {
00941 v[i] = origin[i] - ent->r.absmax[i];
00942 } else {
00943 v[i] = 0;
00944 }
00945 }
00946
00947 dist = VectorLength( v );
00948 if ( dist >= radius ) {
00949 continue;
00950 }
00951
00952
00953 VectorSubtract (ent->r.currentOrigin, origin, dir);
00954
00955
00956 dir[2] += 24;
00957 G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
00958 ent->kamikazeTime = level.time + 3000;
00959
00960 }
00961 }
00962
00963
00964
00965
00966
00967
00968 static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
00969 float dist;
00970 gentity_t *ent;
00971 int entityList[MAX_GENTITIES];
00972 int numListedEntities;
00973 vec3_t mins, maxs;
00974 vec3_t v;
00975 vec3_t dir;
00976 int i, e;
00977
00978 if ( radius < 1 )
00979 radius = 1;
00980
00981 for ( i = 0 ; i < 3 ; i++ ) {
00982 mins[i] = origin[i] - radius;
00983 maxs[i] = origin[i] + radius;
00984 }
00985
00986 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
00987
00988 for ( e = 0 ; e < numListedEntities ; e++ ) {
00989 ent = &g_entities[entityList[ e ]];
00990
00991
00992 if( ent->kamikazeShockTime > level.time ) {
00993 continue;
00994 }
00995
00996
00997 for ( i = 0 ; i < 3 ; i++ ) {
00998 if ( origin[i] < ent->r.absmin[i] ) {
00999 v[i] = ent->r.absmin[i] - origin[i];
01000 } else if ( origin[i] > ent->r.absmax[i] ) {
01001 v[i] = origin[i] - ent->r.absmax[i];
01002 } else {
01003 v[i] = 0;
01004 }
01005 }
01006
01007 dist = VectorLength( v );
01008 if ( dist >= radius ) {
01009 continue;
01010 }
01011
01012
01013 VectorSubtract (ent->r.currentOrigin, origin, dir);
01014 dir[2] += 24;
01015 G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
01016
01017 dir[2] = 0;
01018 VectorNormalize(dir);
01019 if ( ent->client ) {
01020 ent->client->ps.velocity[0] = dir[0] * push;
01021 ent->client->ps.velocity[1] = dir[1] * push;
01022 ent->client->ps.velocity[2] = 100;
01023 }
01024 ent->kamikazeShockTime = level.time + 3000;
01025
01026 }
01027 }
01028
01029
01030
01031
01032
01033
01034 static void KamikazeDamage( gentity_t *self ) {
01035 int i;
01036 float t;
01037 gentity_t *ent;
01038 vec3_t newangles;
01039
01040 self->count += 100;
01041
01042 if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
01043
01044 t = self->count - KAMI_SHOCKWAVE_STARTTIME;
01045 KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
01046 }
01047
01048 if (self->count >= KAMI_EXPLODE_STARTTIME) {
01049
01050 t = self->count - KAMI_EXPLODE_STARTTIME;
01051 KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
01052 }
01053
01054
01055 if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
01056 G_FreeEntity( self );
01057 return;
01058 }
01059 self->nextthink = level.time + 100;
01060
01061
01062 newangles[0] = crandom() * 2;
01063 newangles[1] = crandom() * 2;
01064 newangles[2] = 0;
01065 for (i = 0; i < MAX_CLIENTS; i++)
01066 {
01067 ent = &g_entities[i];
01068 if (!ent->inuse)
01069 continue;
01070 if (!ent->client)
01071 continue;
01072
01073 if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
01074 ent->client->ps.velocity[0] += crandom() * 120;
01075 ent->client->ps.velocity[1] += crandom() * 120;
01076 ent->client->ps.velocity[2] = 30 + random() * 25;
01077 }
01078
01079 ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
01080 ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
01081 ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
01082 }
01083 VectorCopy(newangles, self->movedir);
01084 }
01085
01086
01087
01088
01089
01090
01091 void G_StartKamikaze( gentity_t *ent ) {
01092 gentity_t *explosion;
01093 gentity_t *te;
01094 vec3_t snapped;
01095
01096
01097 explosion = G_Spawn();
01098
01099 explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
01100 explosion->eventTime = level.time;
01101
01102 if ( ent->client ) {
01103 VectorCopy( ent->s.pos.trBase, snapped );
01104 }
01105 else {
01106 VectorCopy( ent->activator->s.pos.trBase, snapped );
01107 }
01108 SnapVector( snapped );
01109 G_SetOrigin( explosion, snapped );
01110
01111 explosion->classname = "kamikaze";
01112 explosion->s.pos.trType = TR_STATIONARY;
01113
01114 explosion->kamikazeTime = level.time;
01115
01116 explosion->think = KamikazeDamage;
01117 explosion->nextthink = level.time + 100;
01118 explosion->count = 0;
01119 VectorClear(explosion->movedir);
01120
01121 trap_LinkEntity( explosion );
01122
01123 if (ent->client) {
01124
01125 explosion->activator = ent;
01126
01127 ent->s.eFlags &= ~EF_KAMIKAZE;
01128
01129 G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
01130 }
01131 else {
01132 if ( !strcmp(ent->activator->classname, "bodyque") ) {
01133 explosion->activator = &g_entities[ent->activator->r.ownerNum];
01134 }
01135 else {
01136 explosion->activator = ent->activator;
01137 }
01138 }
01139
01140
01141 te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
01142 te->r.svFlags |= SVF_BROADCAST;
01143 te->s.eventParm = GTS_KAMIKAZE;
01144 }
01145 #endif