00001
00002
00003
00004
00005
00006 #include "b_local.h"
00007 #include "bg_saga.h"
00008
00009 extern int G_ShipSurfaceForSurfName( const char *surfaceName );
00010 extern qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface );
00011 extern void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint );
00012 extern void G_VehUpdateShields( gentity_t *targ );
00013 extern void G_LetGoOfWall( gentity_t *ent );
00014 extern void BG_ClearRocketLock( playerState_t *ps );
00015
00016 void BotDamageNotification(gclient_t *bot, gentity_t *attacker);
00017
00018
00019 void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker);
00020
00021 void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath )
00022 {
00023 if(self->target)
00024 {
00025 G_UseTargets(self, attacker);
00026 }
00027
00028
00029 G_FreeEntity( self );
00030 }
00031
00032 qboolean G_HeavyMelee( gentity_t *attacker )
00033 {
00034 if (g_gametype.integer == GT_SIEGE
00035 && attacker
00036 && attacker->client
00037 && attacker->client->siegeClass != -1
00038 && (bgSiegeClasses[attacker->client->siegeClass].classflags & (1<<CFL_HEAVYMELEE)) )
00039 {
00040 return qtrue;
00041 }
00042 return qfalse;
00043 }
00044
00045 int G_GetHitLocation(gentity_t *target, vec3_t ppoint)
00046 {
00047 vec3_t point, point_dir;
00048 vec3_t forward, right, up;
00049 vec3_t tangles, tcenter;
00050 float tradius;
00051 float udot, fdot, rdot;
00052 int Vertical, Forward, Lateral;
00053 int HitLoc;
00054
00055
00056 if(target->client)
00057 {
00058
00059 VectorSet(tangles, 0, target->r.currentAngles[YAW], 0);
00060 }
00061
00062 AngleVectors(tangles, forward, right, up);
00063
00064
00065 VectorAdd(target->r.absmin, target->r.absmax, tcenter);
00066 VectorScale(tcenter, 0.5, tcenter);
00067
00068
00069 tradius = (fabs(target->r.maxs[0]) + fabs(target->r.maxs[1]) + fabs(target->r.mins[0]) + fabs(target->r.mins[1]))/4;
00070
00071
00072 if(ppoint && !VectorCompare(ppoint, vec3_origin))
00073 {
00074 VectorCopy(ppoint, point);
00075 }
00076 else
00077 {
00078 return HL_NONE;
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 VectorSubtract(point, tcenter, point_dir);
00101 VectorNormalize(point_dir);
00102
00103
00104 udot = DotProduct(up, point_dir);
00105 if(udot>.800)
00106 {
00107 Vertical = 4;
00108 }
00109 else if(udot>.400)
00110 {
00111 Vertical = 3;
00112 }
00113 else if(udot>-.333)
00114 {
00115 Vertical = 2;
00116 }
00117 else if(udot>-.666)
00118 {
00119 Vertical = 1;
00120 }
00121 else
00122 {
00123 Vertical = 0;
00124 }
00125
00126
00127 fdot = DotProduct(forward, point_dir);
00128 if(fdot>.666)
00129 {
00130 Forward = 4;
00131 }
00132 else if(fdot>.333)
00133 {
00134 Forward = 3;
00135 }
00136 else if(fdot>-.333)
00137 {
00138 Forward = 2;
00139 }
00140 else if(fdot>-.666)
00141 {
00142 Forward = 1;
00143 }
00144 else
00145 {
00146 Forward = 0;
00147 }
00148
00149
00150 rdot = DotProduct(right, point_dir);
00151 if(rdot>.666)
00152 {
00153 Lateral = 4;
00154 }
00155 else if(rdot>.333)
00156 {
00157 Lateral = 3;
00158 }
00159 else if(rdot>-.333)
00160 {
00161 Lateral = 2;
00162 }
00163 else if(rdot>-.666)
00164 {
00165 Lateral = 1;
00166 }
00167 else
00168 {
00169 Lateral = 0;
00170 }
00171
00172 HitLoc = Vertical * 25 + Forward * 5 + Lateral;
00173
00174 if(HitLoc <= 10)
00175 {
00176
00177 if ( rdot > 0 )
00178 {
00179 return HL_FOOT_RT;
00180 }
00181 else
00182 {
00183 return HL_FOOT_LT;
00184 }
00185 }
00186 else if(HitLoc <= 50)
00187 {
00188
00189 if ( rdot > 0 )
00190 {
00191 return HL_LEG_RT;
00192 }
00193 else
00194 {
00195 return HL_LEG_LT;
00196 }
00197 }
00198 else if(HitLoc == 56||HitLoc == 60||HitLoc == 61||HitLoc == 65||HitLoc == 66||HitLoc == 70)
00199 {
00200
00201 if ( rdot > 0 )
00202 {
00203 return HL_HAND_RT;
00204 }
00205 else
00206 {
00207 return HL_HAND_LT;
00208 }
00209 }
00210 else if(HitLoc == 83||HitLoc == 87||HitLoc == 88||HitLoc == 92||HitLoc == 93||HitLoc == 97)
00211 {
00212
00213 if ( rdot > 0 )
00214 {
00215 return HL_ARM_RT;
00216 }
00217 else
00218 {
00219 return HL_ARM_LT;
00220 }
00221 }
00222 else if((HitLoc >= 107 && HitLoc <= 109)||(HitLoc >= 112 && HitLoc <= 114)||(HitLoc >= 117 && HitLoc <= 119))
00223 {
00224
00225 return HL_HEAD;
00226 }
00227 else
00228 {
00229 if(udot < 0.3)
00230 {
00231 return HL_WAIST;
00232 }
00233 else if(fdot < 0)
00234 {
00235 if(rdot > 0.4)
00236 {
00237 return HL_BACK_RT;
00238 }
00239 else if(rdot < -0.4)
00240 {
00241 return HL_BACK_LT;
00242 }
00243 else if(fdot < 0)
00244 {
00245 return HL_BACK;
00246 }
00247 }
00248 else
00249 {
00250 if(rdot > 0.3)
00251 {
00252 return HL_CHEST_RT;
00253 }
00254 else if(rdot < -0.3)
00255 {
00256 return HL_CHEST_LT;
00257 }
00258 else if(fdot < 0)
00259 {
00260 return HL_CHEST;
00261 }
00262 }
00263 }
00264 return HL_NONE;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 void ExplodeDeath( gentity_t *self )
00369 {
00370
00371 vec3_t forward;
00372
00373 self->takedamage = qfalse;
00374
00375 self->s.loopSound = 0;
00376 self->s.loopIsSoundset = qfalse;
00377
00378 VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
00379
00380
00381 AngleVectors(self->s.angles, forward, NULL, NULL);
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 {
00392
00393
00394 }
00395
00396 if(self->splashDamage > 0 && self->splashRadius > 0)
00397 {
00398 gentity_t *attacker = self;
00399 if ( self->parent )
00400 {
00401 attacker = self->parent;
00402 }
00403 G_RadiusDamage( self->r.currentOrigin, attacker, self->splashDamage, self->splashRadius,
00404 attacker, NULL, MOD_UNKNOWN );
00405 }
00406
00407 ObjectDie( self, self, self, 20, 0 );
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
00417 gentity_t *plum;
00418
00419 plum = G_TempEntity( origin, EV_SCOREPLUM );
00420
00421 plum->r.svFlags |= SVF_SINGLECLIENT;
00422 plum->r.singleClient = ent->s.number;
00423
00424 plum->s.otherEntityNum = ent->s.number;
00425 plum->s.time = score;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435 extern qboolean g_dontPenalizeTeam;
00436 void AddScore( gentity_t *ent, vec3_t origin, int score )
00437 {
00438
00439
00440
00441
00442
00443
00444
00445 if ( !ent->client ) {
00446 return;
00447 }
00448
00449 if ( level.warmupTime ) {
00450 return;
00451 }
00452
00453
00454
00455 ent->client->ps.persistant[PERS_SCORE] += score;
00456 if ( g_gametype.integer == GT_TEAM && !g_dontPenalizeTeam )
00457 level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
00458 CalculateRanks();
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468 void TossClientWeapon(gentity_t *self, vec3_t direction, float speed)
00469 {
00470 vec3_t vel;
00471 gitem_t *item;
00472 gentity_t *launched;
00473 int weapon = self->s.weapon;
00474 int ammoSub;
00475
00476 if (g_gametype.integer == GT_SIEGE)
00477 {
00478 return;
00479 }
00480
00481 if (weapon <= WP_BRYAR_PISTOL)
00482 {
00483 return;
00484 }
00485
00486 if (weapon == WP_EMPLACED_GUN ||
00487 weapon == WP_TURRET)
00488 {
00489 return;
00490 }
00491
00492
00493 item = BG_FindItemForWeapon( weapon );
00494
00495 ammoSub = (self->client->ps.ammo[weaponData[weapon].ammoIndex] - bg_itemlist[BG_GetItemIndexByTag(weapon, IT_WEAPON)].quantity);
00496
00497 if (ammoSub < 0)
00498 {
00499 int ammoQuan = item->quantity;
00500 ammoQuan -= (-ammoSub);
00501
00502 if (ammoQuan <= 0)
00503 {
00504 return;
00505 }
00506 }
00507
00508 vel[0] = direction[0]*speed;
00509 vel[1] = direction[1]*speed;
00510 vel[2] = direction[2]*speed;
00511
00512 launched = LaunchItem(item, self->client->ps.origin, vel);
00513
00514 launched->s.generic1 = self->s.number;
00515 launched->s.powerups = level.time + 1500;
00516
00517 launched->count = bg_itemlist[BG_GetItemIndexByTag(weapon, IT_WEAPON)].quantity;
00518
00519 self->client->ps.ammo[weaponData[weapon].ammoIndex] -= bg_itemlist[BG_GetItemIndexByTag(weapon, IT_WEAPON)].quantity;
00520
00521 if (self->client->ps.ammo[weaponData[weapon].ammoIndex] < 0)
00522 {
00523 launched->count -= (-self->client->ps.ammo[weaponData[weapon].ammoIndex]);
00524 self->client->ps.ammo[weaponData[weapon].ammoIndex] = 0;
00525 }
00526
00527 if ((self->client->ps.ammo[weaponData[weapon].ammoIndex] < 1 && weapon != WP_DET_PACK) ||
00528 (weapon != WP_THERMAL && weapon != WP_DET_PACK && weapon != WP_TRIP_MINE))
00529 {
00530 int i = 0;
00531 int weap = -1;
00532
00533 self->client->ps.stats[STAT_WEAPONS] &= ~(1 << weapon);
00534
00535 while (i < WP_NUM_WEAPONS)
00536 {
00537 if ((self->client->ps.stats[STAT_WEAPONS] & (1 << i)) && i != WP_NONE)
00538 {
00539 weap = i;
00540 break;
00541 }
00542 i++;
00543 }
00544
00545 if (weap != -1)
00546 {
00547 self->s.weapon = weap;
00548 self->client->ps.weapon = weap;
00549 }
00550 else
00551 {
00552 self->s.weapon = 0;
00553 self->client->ps.weapon = 0;
00554 }
00555
00556 G_AddEvent(self, EV_NOAMMO, weapon);
00557 }
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567 void TossClientItems( gentity_t *self ) {
00568 gitem_t *item;
00569 int weapon;
00570 float angle;
00571 int i;
00572 gentity_t *drop;
00573
00574 if (g_gametype.integer == GT_SIEGE)
00575 {
00576 return;
00577 }
00578
00579
00580 weapon = self->s.weapon;
00581
00582
00583
00584
00585
00586 if ( weapon == WP_BRYAR_PISTOL) {
00587 if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
00588 weapon = self->client->pers.cmd.weapon;
00589 }
00590 if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
00591 weapon = WP_NONE;
00592 }
00593 }
00594
00595 self->s.bolt2 = weapon;
00596
00597 if ( weapon > WP_BRYAR_PISTOL &&
00598 weapon != WP_EMPLACED_GUN &&
00599 weapon != WP_TURRET &&
00600 self->client->ps.ammo[ weaponData[weapon].ammoIndex ] ) {
00601 gentity_t *te;
00602
00603
00604 item = BG_FindItemForWeapon( weapon );
00605
00606
00607 te = G_TempEntity( vec3_origin, EV_DESTROY_WEAPON_MODEL );
00608 te->r.svFlags |= SVF_BROADCAST;
00609 te->s.eventParm = self->s.number;
00610
00611
00612 Drop_Item( self, item, 0 );
00613 }
00614
00615
00616 if ( g_gametype.integer != GT_TEAM && g_gametype.integer != GT_SIEGE ) {
00617 angle = 45;
00618 for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
00619 if ( self->client->ps.powerups[ i ] > level.time ) {
00620 item = BG_FindItemForPowerup( i );
00621 if ( !item ) {
00622 continue;
00623 }
00624 drop = Drop_Item( self, item, angle );
00625
00626 drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
00627 if ( drop->count < 1 ) {
00628 drop->count = 1;
00629 }
00630 angle += 45;
00631 }
00632 }
00633 }
00634 }
00635
00636
00637
00638
00639
00640
00641
00642 void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
00643 vec3_t dir;
00644 vec3_t angles;
00645
00646 if ( attacker && attacker != self ) {
00647 VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
00648 } else if ( inflictor && inflictor != self ) {
00649 VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
00650 } else {
00651 self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
00652 return;
00653 }
00654
00655 self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
00656
00657 angles[YAW] = vectoyaw ( dir );
00658 angles[PITCH] = 0;
00659 angles[ROLL] = 0;
00660 }
00661
00662
00663
00664
00665
00666
00667 void GibEntity( gentity_t *self, int killer ) {
00668 G_AddEvent( self, EV_GIB_PLAYER, killer );
00669 self->takedamage = qfalse;
00670 self->s.eType = ET_INVISIBLE;
00671 self->r.contents = 0;
00672 }
00673
00674 void BodyRid(gentity_t *ent)
00675 {
00676 trap_UnlinkEntity( ent );
00677 ent->physicsObject = qfalse;
00678 }
00679
00680
00681
00682
00683
00684
00685 void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
00686
00687 qboolean doDisint = qfalse;
00688
00689 if (self->s.eType == ET_NPC)
00690 {
00691 if ( self->client && self->client->ps.torsoTimer <= 0 &&
00692 (meansOfDeath == MOD_UNKNOWN ||
00693 meansOfDeath == MOD_WATER ||
00694 meansOfDeath == MOD_SLIME ||
00695 meansOfDeath == MOD_LAVA ||
00696 meansOfDeath == MOD_CRUSH ||
00697 meansOfDeath == MOD_TELEFRAG ||
00698 meansOfDeath == MOD_FALLING ||
00699 meansOfDeath == MOD_SUICIDE ||
00700 meansOfDeath == MOD_TARGET_LASER ||
00701 meansOfDeath == MOD_TRIGGER_HURT) )
00702 {
00703 self->think = G_FreeEntity;
00704 self->nextthink = level.time;
00705 }
00706 return;
00707 }
00708
00709 if (self->health < (GIB_HEALTH+1))
00710 {
00711 self->health = GIB_HEALTH+1;
00712
00713 if (self->client && (level.time - self->client->respawnTime) < 2000)
00714 {
00715 doDisint = qfalse;
00716 }
00717 else
00718 {
00719 doDisint = qtrue;
00720 }
00721 }
00722
00723 if (self->client && (self->client->ps.eFlags & EF_DISINTEGRATION))
00724 {
00725 return;
00726 }
00727 else if (self->s.eFlags & EF_DISINTEGRATION)
00728 {
00729 return;
00730 }
00731
00732 if (doDisint)
00733 {
00734 if (self->client)
00735 {
00736 self->client->ps.eFlags |= EF_DISINTEGRATION;
00737 VectorCopy(self->client->ps.origin, self->client->ps.lastHitLoc);
00738 }
00739 else
00740 {
00741 self->s.eFlags |= EF_DISINTEGRATION;
00742 VectorCopy(self->r.currentOrigin, self->s.origin2);
00743
00744
00745 self->think = BodyRid;
00746 self->nextthink = level.time + 1000;
00747 }
00748 return;
00749 }
00750 }
00751
00752
00753
00754 char *modNames[MOD_MAX] = {
00755 "MOD_UNKNOWN",
00756 "MOD_STUN_BATON",
00757 "MOD_MELEE",
00758 "MOD_SABER",
00759 "MOD_BRYAR_PISTOL",
00760 "MOD_BRYAR_PISTOL_ALT",
00761 "MOD_BLASTER",
00762 "MOD_TURBLAST",
00763 "MOD_DISRUPTOR",
00764 "MOD_DISRUPTOR_SPLASH",
00765 "MOD_DISRUPTOR_SNIPER",
00766 "MOD_BOWCASTER",
00767 "MOD_REPEATER",
00768 "MOD_REPEATER_ALT",
00769 "MOD_REPEATER_ALT_SPLASH",
00770 "MOD_DEMP2",
00771 "MOD_DEMP2_ALT",
00772 "MOD_FLECHETTE",
00773 "MOD_FLECHETTE_ALT_SPLASH",
00774 "MOD_ROCKET",
00775 "MOD_ROCKET_SPLASH",
00776 "MOD_ROCKET_HOMING",
00777 "MOD_ROCKET_HOMING_SPLASH",
00778 "MOD_THERMAL",
00779 "MOD_THERMAL_SPLASH",
00780 "MOD_TRIP_MINE_SPLASH",
00781 "MOD_TIMED_MINE_SPLASH",
00782 "MOD_DET_PACK_SPLASH",
00783 "MOD_VEHICLE",
00784 "MOD_CONC",
00785 "MOD_CONC_ALT",
00786 "MOD_FORCE_DARK",
00787 "MOD_SENTRY",
00788 "MOD_WATER",
00789 "MOD_SLIME",
00790 "MOD_LAVA",
00791 "MOD_CRUSH",
00792 "MOD_TELEFRAG",
00793 "MOD_FALLING",
00794 "MOD_SUICIDE",
00795 "MOD_TARGET_LASER",
00796 "MOD_TRIGGER_HURT"
00797 };
00798
00799
00800
00801
00802
00803
00804
00805 void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
00806 #if 0
00807 gentity_t *ent;
00808 vec3_t dir;
00809 char *classname;
00810
00811
00812 if ( self->client->ps.powerups[PW_REDFLAG] ||
00813 self->client->ps.powerups[PW_BLUEFLAG] ||
00814 self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00815
00816 if ( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY ) {
00817 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00818 classname = "team_CTF_blueflag";
00819 }
00820 else {
00821 classname = "team_CTF_redflag";
00822 }
00823 }
00824 else {
00825 if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00826 classname = "team_CTF_redflag";
00827 }
00828 else {
00829 classname = "team_CTF_blueflag";
00830 }
00831 }
00832 ent = NULL;
00833 do
00834 {
00835 ent = G_Find(ent, FOFS(classname), classname);
00836 } while (ent && (ent->flags & FL_DROPPED_ITEM));
00837
00838 if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
00839
00840 VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00841 if ( VectorLength(dir) < 200 ) {
00842 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00843 if ( attacker->client ) {
00844 attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00845 }
00846 }
00847 }
00848 }
00849 #endif
00850 }
00851
00852 qboolean G_InKnockDown( playerState_t *ps )
00853 {
00854 switch ( (ps->legsAnim) )
00855 {
00856 case BOTH_KNOCKDOWN1:
00857 case BOTH_KNOCKDOWN2:
00858 case BOTH_KNOCKDOWN3:
00859 case BOTH_KNOCKDOWN4:
00860 case BOTH_KNOCKDOWN5:
00861 return qtrue;
00862 break;
00863 case BOTH_GETUP1:
00864 case BOTH_GETUP2:
00865 case BOTH_GETUP3:
00866 case BOTH_GETUP4:
00867 case BOTH_GETUP5:
00868 case BOTH_FORCE_GETUP_F1:
00869 case BOTH_FORCE_GETUP_F2:
00870 case BOTH_FORCE_GETUP_B1:
00871 case BOTH_FORCE_GETUP_B2:
00872 case BOTH_FORCE_GETUP_B3:
00873 case BOTH_FORCE_GETUP_B4:
00874 case BOTH_FORCE_GETUP_B5:
00875 return qtrue;
00876 break;
00877 }
00878 return qfalse;
00879 }
00880
00881 static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc )
00882 {
00883 int deathAnim = -1;
00884
00885 if ( BG_InRoll( &self->client->ps, self->client->ps.legsAnim ) )
00886 {
00887 deathAnim = BOTH_DEATH_ROLL;
00888 }
00889 else if ( BG_FlippingAnim( self->client->ps.legsAnim ) )
00890 {
00891 deathAnim = BOTH_DEATH_FLIP;
00892 }
00893 else if ( G_InKnockDown( &self->client->ps ) )
00894 {
00895 int animLength = bgAllAnims[self->localAnimIndex].anims[self->client->ps.legsAnim].numFrames * fabs((float)(bgHumanoidAnimations[self->client->ps.legsAnim].frameLerp));
00896 switch ( self->client->ps.legsAnim )
00897 {
00898 case BOTH_KNOCKDOWN1:
00899 if ( animLength - self->client->ps.legsTimer > 100 )
00900 {
00901 if ( self->client->ps.legsTimer > 600 )
00902 {
00903 deathAnim = BOTH_DEATH_FALLING_UP;
00904 }
00905 else
00906 {
00907 deathAnim = BOTH_DEATH_LYING_UP;
00908 }
00909 }
00910 break;
00911 case BOTH_KNOCKDOWN2:
00912 if ( animLength - self->client->ps.legsTimer > 700 )
00913 {
00914 if ( self->client->ps.legsTimer > 600 )
00915 {
00916 deathAnim = BOTH_DEATH_FALLING_UP;
00917 }
00918 else
00919 {
00920 deathAnim = BOTH_DEATH_LYING_UP;
00921 }
00922 }
00923 break;
00924 case BOTH_KNOCKDOWN3:
00925 if ( animLength - self->client->ps.legsTimer > 100 )
00926 {
00927 if ( self->client->ps.legsTimer > 1300 )
00928 {
00929 deathAnim = BOTH_DEATH_FALLING_DN;
00930 }
00931 else
00932 {
00933 deathAnim = BOTH_DEATH_LYING_DN;
00934 }
00935 }
00936 break;
00937 case BOTH_KNOCKDOWN4:
00938 if ( animLength - self->client->ps.legsTimer > 300 )
00939 {
00940 if ( self->client->ps.legsTimer > 350 )
00941 {
00942 deathAnim = BOTH_DEATH_FALLING_UP;
00943 }
00944 else
00945 {
00946 deathAnim = BOTH_DEATH_LYING_UP;
00947 }
00948 }
00949 else
00950 {
00951 vec3_t fwd;
00952 float thrown = 0;
00953
00954 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
00955 thrown = DotProduct( fwd, self->client->ps.velocity );
00956
00957 if ( thrown < -150 )
00958 {
00959 deathAnim = BOTH_DEATHBACKWARD1;
00960 }
00961 else
00962 {
00963 deathAnim = BOTH_DEATH_CROUCHED;
00964 }
00965 }
00966 break;
00967 case BOTH_KNOCKDOWN5:
00968 if ( self->client->ps.legsTimer < 750 )
00969 {
00970 deathAnim = BOTH_DEATH_LYING_DN;
00971 }
00972 break;
00973 case BOTH_GETUP1:
00974 if ( self->client->ps.legsTimer < 350 )
00975 {
00976 }
00977 else if ( self->client->ps.legsTimer < 800 )
00978 {
00979 vec3_t fwd;
00980 float thrown = 0;
00981
00982 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
00983 thrown = DotProduct( fwd, self->client->ps.velocity );
00984 if ( thrown < -150 )
00985 {
00986 deathAnim = BOTH_DEATHBACKWARD1;
00987 }
00988 else
00989 {
00990 deathAnim = BOTH_DEATH_CROUCHED;
00991 }
00992 }
00993 else
00994 {
00995 if ( animLength - self->client->ps.legsTimer > 450 )
00996 {
00997 deathAnim = BOTH_DEATH_FALLING_UP;
00998 }
00999 else
01000 {
01001 deathAnim = BOTH_DEATH_LYING_UP;
01002 }
01003 }
01004 break;
01005 case BOTH_GETUP2:
01006 if ( self->client->ps.legsTimer < 150 )
01007 {
01008 }
01009 else if ( self->client->ps.legsTimer < 850 )
01010 {
01011 vec3_t fwd;
01012 float thrown = 0;
01013
01014 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01015 thrown = DotProduct( fwd, self->client->ps.velocity );
01016
01017 if ( thrown < -150 )
01018 {
01019 deathAnim = BOTH_DEATHBACKWARD1;
01020 }
01021 else
01022 {
01023 deathAnim = BOTH_DEATH_CROUCHED;
01024 }
01025 }
01026 else
01027 {
01028 if ( animLength - self->client->ps.legsTimer > 500 )
01029 {
01030 deathAnim = BOTH_DEATH_FALLING_UP;
01031 }
01032 else
01033 {
01034 deathAnim = BOTH_DEATH_LYING_UP;
01035 }
01036 }
01037 break;
01038 case BOTH_GETUP3:
01039 if ( self->client->ps.legsTimer < 250 )
01040 {
01041 }
01042 else if ( self->client->ps.legsTimer < 600 )
01043 {
01044 vec3_t fwd;
01045 float thrown = 0;
01046 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01047 thrown = DotProduct( fwd, self->client->ps.velocity );
01048
01049 if ( thrown < -150 )
01050 {
01051 deathAnim = BOTH_DEATHBACKWARD1;
01052 }
01053 else
01054 {
01055 deathAnim = BOTH_DEATH_CROUCHED;
01056 }
01057 }
01058 else
01059 {
01060 if ( animLength - self->client->ps.legsTimer > 150 )
01061 {
01062 deathAnim = BOTH_DEATH_FALLING_DN;
01063 }
01064 else
01065 {
01066 deathAnim = BOTH_DEATH_LYING_DN;
01067 }
01068 }
01069 break;
01070 case BOTH_GETUP4:
01071 if ( self->client->ps.legsTimer < 250 )
01072 {
01073 }
01074 else if ( self->client->ps.legsTimer < 600 )
01075 {
01076 vec3_t fwd;
01077 float thrown = 0;
01078
01079 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01080 thrown = DotProduct( fwd, self->client->ps.velocity );
01081
01082 if ( thrown < -150 )
01083 {
01084 deathAnim = BOTH_DEATHBACKWARD1;
01085 }
01086 else
01087 {
01088 deathAnim = BOTH_DEATH_CROUCHED;
01089 }
01090 }
01091 else
01092 {
01093 if ( animLength - self->client->ps.legsTimer > 850 )
01094 {
01095 deathAnim = BOTH_DEATH_FALLING_DN;
01096 }
01097 else
01098 {
01099 deathAnim = BOTH_DEATH_LYING_UP;
01100 }
01101 }
01102 break;
01103 case BOTH_GETUP5:
01104 if ( self->client->ps.legsTimer > 850 )
01105 {
01106 if ( animLength - self->client->ps.legsTimer > 1500 )
01107 {
01108 deathAnim = BOTH_DEATH_FALLING_DN;
01109 }
01110 else
01111 {
01112 deathAnim = BOTH_DEATH_LYING_DN;
01113 }
01114 }
01115 break;
01116 case BOTH_GETUP_CROUCH_B1:
01117 if ( self->client->ps.legsTimer < 800 )
01118 {
01119 vec3_t fwd;
01120 float thrown = 0;
01121
01122 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01123 thrown = DotProduct( fwd, self->client->ps.velocity );
01124
01125 if ( thrown < -150 )
01126 {
01127 deathAnim = BOTH_DEATHBACKWARD1;
01128 }
01129 else
01130 {
01131 deathAnim = BOTH_DEATH_CROUCHED;
01132 }
01133 }
01134 else
01135 {
01136 if ( animLength - self->client->ps.legsTimer > 400 )
01137 {
01138 deathAnim = BOTH_DEATH_FALLING_UP;
01139 }
01140 else
01141 {
01142 deathAnim = BOTH_DEATH_LYING_UP;
01143 }
01144 }
01145 break;
01146 case BOTH_GETUP_CROUCH_F1:
01147 if ( self->client->ps.legsTimer < 800 )
01148 {
01149 vec3_t fwd;
01150 float thrown = 0;
01151
01152 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01153 thrown = DotProduct( fwd, self->client->ps.velocity );
01154
01155 if ( thrown < -150 )
01156 {
01157 deathAnim = BOTH_DEATHBACKWARD1;
01158 }
01159 else
01160 {
01161 deathAnim = BOTH_DEATH_CROUCHED;
01162 }
01163 }
01164 else
01165 {
01166 if ( animLength - self->client->ps.legsTimer > 150 )
01167 {
01168 deathAnim = BOTH_DEATH_FALLING_DN;
01169 }
01170 else
01171 {
01172 deathAnim = BOTH_DEATH_LYING_DN;
01173 }
01174 }
01175 break;
01176 case BOTH_FORCE_GETUP_B1:
01177 if ( self->client->ps.legsTimer < 325 )
01178 {
01179 }
01180 else if ( self->client->ps.legsTimer < 725 )
01181 {
01182 deathAnim = BOTH_DEATH_SPIN_180;
01183 }
01184 else if ( self->client->ps.legsTimer < 900 )
01185 {
01186 vec3_t fwd;
01187 float thrown = 0;
01188
01189 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01190 thrown = DotProduct( fwd, self->client->ps.velocity );
01191
01192 if ( thrown < -150 )
01193 {
01194 deathAnim = BOTH_DEATHBACKWARD1;
01195 }
01196 else
01197 {
01198 deathAnim = BOTH_DEATH_CROUCHED;
01199 }
01200 }
01201 else
01202 {
01203 if ( animLength - self->client->ps.legsTimer > 50 )
01204 {
01205 deathAnim = BOTH_DEATH_FALLING_UP;
01206 }
01207 else
01208 {
01209 deathAnim = BOTH_DEATH_LYING_UP;
01210 }
01211 }
01212 break;
01213 case BOTH_FORCE_GETUP_B2:
01214 if ( self->client->ps.legsTimer < 575 )
01215 {
01216 }
01217 else if ( self->client->ps.legsTimer < 875 )
01218 {
01219 deathAnim = BOTH_DEATH_SPIN_180;
01220 }
01221 else if ( self->client->ps.legsTimer < 900 )
01222 {
01223 vec3_t fwd;
01224 float thrown = 0;
01225
01226 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01227 thrown = DotProduct( fwd, self->client->ps.velocity );
01228
01229 if ( thrown < -150 )
01230 {
01231 deathAnim = BOTH_DEATHBACKWARD1;
01232 }
01233 else
01234 {
01235 deathAnim = BOTH_DEATH_CROUCHED;
01236 }
01237 }
01238 else
01239 {
01240
01241 deathAnim = BOTH_DEATH_FALLING_UP;
01242 }
01243 break;
01244 case BOTH_FORCE_GETUP_B3:
01245 if ( self->client->ps.legsTimer < 150 )
01246 {
01247 }
01248 else if ( self->client->ps.legsTimer < 775 )
01249 {
01250 deathAnim = BOTH_DEATHBACKWARD2;
01251 }
01252 else
01253 {
01254
01255 deathAnim = BOTH_DEATH_FALLING_UP;
01256 }
01257 break;
01258 case BOTH_FORCE_GETUP_B4:
01259 if ( self->client->ps.legsTimer < 325 )
01260 {
01261 }
01262 else
01263 {
01264 if ( animLength - self->client->ps.legsTimer > 150 )
01265 {
01266 deathAnim = BOTH_DEATH_FALLING_UP;
01267 }
01268 else
01269 {
01270 deathAnim = BOTH_DEATH_LYING_UP;
01271 }
01272 }
01273 break;
01274 case BOTH_FORCE_GETUP_B5:
01275 if ( self->client->ps.legsTimer < 550 )
01276 {
01277 }
01278 else if ( self->client->ps.legsTimer < 1025 )
01279 {
01280 deathAnim = BOTH_DEATHBACKWARD2;
01281 }
01282 else
01283 {
01284 if ( animLength - self->client->ps.legsTimer > 50 )
01285 {
01286 deathAnim = BOTH_DEATH_FALLING_UP;
01287 }
01288 else
01289 {
01290 deathAnim = BOTH_DEATH_LYING_UP;
01291 }
01292 }
01293 break;
01294 case BOTH_FORCE_GETUP_B6:
01295 if ( self->client->ps.legsTimer < 225 )
01296 {
01297 }
01298 else if ( self->client->ps.legsTimer < 425 )
01299 {
01300 vec3_t fwd;
01301 float thrown = 0;
01302
01303 AngleVectors( self->client->ps.viewangles, fwd, NULL, NULL );
01304 thrown = DotProduct( fwd, self->client->ps.velocity );
01305
01306 if ( thrown < -150 )
01307 {
01308 deathAnim = BOTH_DEATHBACKWARD1;
01309 }
01310 else
01311 {
01312 deathAnim = BOTH_DEATH_CROUCHED;
01313 }
01314 }
01315 else if ( self->client->ps.legsTimer < 825 )
01316 {
01317 deathAnim = BOTH_DEATHFORWARD3;
01318 }
01319 else
01320 {
01321 if ( animLength - self->client->ps.legsTimer > 225 )
01322 {
01323 deathAnim = BOTH_DEATH_FALLING_UP;
01324 }
01325 else
01326 {
01327 deathAnim = BOTH_DEATH_LYING_UP;
01328 }
01329 }
01330 break;
01331 case BOTH_FORCE_GETUP_F1:
01332 if ( self->client->ps.legsTimer < 275 )
01333 {
01334 }
01335 else if ( self->client->ps.legsTimer < 750 )
01336 {
01337 deathAnim = BOTH_DEATH14;
01338 }
01339 else
01340 {
01341 if ( animLength - self->client->ps.legsTimer > 100 )
01342 {
01343 deathAnim = BOTH_DEATH_FALLING_DN;
01344 }
01345 else
01346 {
01347 deathAnim = BOTH_DEATH_LYING_DN;
01348 }
01349 }
01350 break;
01351 case BOTH_FORCE_GETUP_F2:
01352 if ( self->client->ps.legsTimer < 1200 )
01353 {
01354 }
01355 else
01356 {
01357 if ( animLength - self->client->ps.legsTimer > 225 )
01358 {
01359 deathAnim = BOTH_DEATH_FALLING_DN;
01360 }
01361 else
01362 {
01363 deathAnim = BOTH_DEATH_LYING_DN;
01364 }
01365 }
01366 break;
01367 }
01368 }
01369
01370 return deathAnim;
01371 }
01372
01373 int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc )
01374 {
01375 int deathAnim = -1;
01376 int max_health;
01377 int legAnim = 0;
01378 vec3_t objVelocity;
01379
01380 if (!self || !self->client)
01381 {
01382 if (!self || self->s.eType != ET_NPC)
01383 {
01384 return 0;
01385 }
01386 }
01387
01388 if (self->client)
01389 {
01390 max_health = self->client->ps.stats[STAT_MAX_HEALTH];
01391
01392 if (self->client->inSpaceIndex && self->client->inSpaceIndex != ENTITYNUM_NONE)
01393 {
01394 return BOTH_CHOKE3;
01395 }
01396 }
01397 else
01398 {
01399 max_health = 60;
01400 }
01401
01402 if (self->client)
01403 {
01404 VectorCopy(self->client->ps.velocity, objVelocity);
01405 }
01406 else
01407 {
01408 VectorCopy(self->s.pos.trDelta, objVelocity);
01409 }
01410
01411 if ( hitLoc == HL_NONE )
01412 {
01413 hitLoc = G_GetHitLocation( self, point );
01414 }
01415
01416 if (self->client)
01417 {
01418 legAnim = self->client->ps.legsAnim;
01419 }
01420 else
01421 {
01422 legAnim = self->s.legsAnim;
01423 }
01424
01425 if (gGAvoidDismember)
01426 {
01427 return BOTH_RIGHTHANDCHOPPEDOFF;
01428 }
01429
01430
01431 switch( legAnim )
01432 {
01433 case BOTH_DEATH1:
01434 case BOTH_DEAD1:
01435 case BOTH_DEATH2:
01436 case BOTH_DEAD2:
01437 case BOTH_DEATH8:
01438 case BOTH_DEAD8:
01439 case BOTH_DEATH13:
01440 case BOTH_DEAD13:
01441 case BOTH_DEATH14:
01442 case BOTH_DEAD14:
01443 case BOTH_DEATH16:
01444 case BOTH_DEAD16:
01445 case BOTH_DEADBACKWARD1:
01446 case BOTH_DEADBACKWARD2:
01447 deathAnim = -2;
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462 case BOTH_DEATH10:
01463 case BOTH_DEAD10:
01464 case BOTH_DEATH15:
01465 case BOTH_DEAD15:
01466 case BOTH_DEADFORWARD1:
01467 case BOTH_DEADFORWARD2:
01468 deathAnim = -2;
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 case BOTH_DEADFLOP1:
01481 deathAnim = -2;
01482
01483 break;
01484 case BOTH_DEAD3:
01485 case BOTH_DEAD4:
01486 case BOTH_DEAD5:
01487 case BOTH_DEAD6:
01488 case BOTH_DEAD7:
01489 case BOTH_DEAD9:
01490 case BOTH_DEAD11:
01491 case BOTH_DEAD12:
01492 case BOTH_DEAD17:
01493 case BOTH_DEAD18:
01494 case BOTH_DEAD19:
01495 case BOTH_LYINGDEAD1:
01496 case BOTH_STUMBLEDEAD1:
01497 case BOTH_FALLDEAD1LAND:
01498 case BOTH_DEATH3:
01499 case BOTH_DEATH4:
01500 case BOTH_DEATH5:
01501 case BOTH_DEATH6:
01502 case BOTH_DEATH7:
01503 case BOTH_DEATH9:
01504 case BOTH_DEATH11:
01505 case BOTH_DEATH12:
01506 case BOTH_DEATH17:
01507 case BOTH_DEATH18:
01508 case BOTH_DEATH19:
01509 case BOTH_DEATHFORWARD1:
01510 case BOTH_DEATHFORWARD2:
01511 case BOTH_DEATHBACKWARD1:
01512 case BOTH_DEATHBACKWARD2:
01513 case BOTH_DEATH1IDLE:
01514 case BOTH_LYINGDEATH1:
01515 case BOTH_STUMBLEDEATH1:
01516 case BOTH_FALLDEATH1:
01517 case BOTH_FALLDEATH1INAIR:
01518 case BOTH_FALLDEATH1LAND:
01519 deathAnim = -2;
01520 break;
01521 }
01522 if ( deathAnim == -1 )
01523 {
01524 if (self->client)
01525 {
01526 deathAnim = G_CheckSpecialDeathAnim( self, point, damage, mod, hitLoc );
01527 }
01528
01529 if (deathAnim == -1)
01530 {
01531
01532 switch( hitLoc )
01533 {
01534 case HL_FOOT_RT:
01535 case HL_FOOT_LT:
01536 if ( mod == MOD_SABER && !Q_irand( 0, 2 ) )
01537 {
01538 return BOTH_DEATH10;
01539 }
01540 else if ( !Q_irand( 0, 2 ) )
01541 {
01542 deathAnim = BOTH_DEATH4;
01543 }
01544 else if ( !Q_irand( 0, 1 ) )
01545 {
01546 deathAnim = BOTH_DEATH5;
01547 }
01548 else
01549 {
01550 deathAnim = BOTH_DEATH15;
01551 }
01552 break;
01553 case HL_LEG_RT:
01554 if ( !Q_irand( 0, 2 ) )
01555 {
01556 deathAnim = BOTH_DEATH4;
01557 }
01558 else if ( !Q_irand( 0, 1 ) )
01559 {
01560 deathAnim = BOTH_DEATH5;
01561 }
01562 else
01563 {
01564 deathAnim = BOTH_DEATH15;
01565 }
01566 break;
01567 case HL_LEG_LT:
01568 if ( !Q_irand( 0, 2 ) )
01569 {
01570 deathAnim = BOTH_DEATH4;
01571 }
01572 else if ( !Q_irand( 0, 1 ) )
01573 {
01574 deathAnim = BOTH_DEATH5;
01575 }
01576 else
01577 {
01578 deathAnim = BOTH_DEATH15;
01579 }
01580 break;
01581 case HL_BACK:
01582 if ( !VectorLengthSquared( objVelocity ) )
01583 {
01584 deathAnim = BOTH_DEATH17;
01585 }
01586 else
01587 {
01588 if ( !Q_irand( 0, 2 ) )
01589 {
01590 deathAnim = BOTH_DEATH4;
01591 }
01592 else if ( !Q_irand( 0, 1 ) )
01593 {
01594 deathAnim = BOTH_DEATH5;
01595 }
01596 else
01597 {
01598 deathAnim = BOTH_DEATH15;
01599 }
01600 }
01601 break;
01602 case HL_CHEST_RT:
01603 case HL_ARM_RT:
01604 case HL_HAND_RT:
01605 case HL_BACK_RT:
01606 if ( damage <= max_health*0.25 )
01607 {
01608 deathAnim = BOTH_DEATH9;
01609 }
01610 else if ( damage <= max_health*0.5 )
01611 {
01612 deathAnim = BOTH_DEATH3;
01613 }
01614 else if ( damage <= max_health*0.75 )
01615 {
01616 deathAnim = BOTH_DEATH6;
01617 }
01618 else
01619 {
01620
01621 if ( Q_irand( 0, 1 ) )
01622 {
01623 deathAnim = BOTH_DEATH8;
01624 }
01625 else
01626 {
01627 switch ( Q_irand( 0, 2 ) )
01628 {
01629 default:
01630 case 0:
01631 deathAnim = BOTH_DEATH9;
01632 break;
01633 case 1:
01634 deathAnim = BOTH_DEATH3;
01635 break;
01636 case 2:
01637 deathAnim = BOTH_DEATH6;
01638 break;
01639 }
01640 }
01641 }
01642 break;
01643 case HL_CHEST_LT:
01644 case HL_ARM_LT:
01645 case HL_HAND_LT:
01646 case HL_BACK_LT:
01647 if ( damage <= max_health*0.25 )
01648 {
01649 deathAnim = BOTH_DEATH11;
01650 }
01651 else if ( damage <= max_health*0.5 )
01652 {
01653 deathAnim = BOTH_DEATH7;
01654 }
01655 else if ( damage <= max_health*0.75 )
01656 {
01657 deathAnim = BOTH_DEATH12;
01658 }
01659 else
01660 {
01661
01662 if ( Q_irand( 0, 1 ) )
01663 {
01664 deathAnim = BOTH_DEATH14;
01665 }
01666 else
01667 {
01668 switch ( Q_irand( 0, 2 ) )
01669 {
01670 default:
01671 case 0:
01672 deathAnim = BOTH_DEATH11;
01673 break;
01674 case 1:
01675 deathAnim = BOTH_DEATH7;
01676 break;
01677 case 2:
01678 deathAnim = BOTH_DEATH12;
01679 break;
01680 }
01681 }
01682 }
01683 break;
01684 case HL_CHEST:
01685 case HL_WAIST:
01686 if ( damage <= max_health*0.25 || !VectorLengthSquared( objVelocity ) )
01687 {
01688 if ( !Q_irand( 0, 1 ) )
01689 {
01690 deathAnim = BOTH_DEATH18;
01691 }
01692 else
01693 {
01694 deathAnim = BOTH_DEATH19;
01695 }
01696 }
01697 else if ( damage <= max_health*0.5 )
01698 {
01699 deathAnim = BOTH_DEATH2;
01700 }
01701 else if ( damage <= max_health*0.75 )
01702 {
01703 if ( !Q_irand( 0, 1 ) )
01704 {
01705 deathAnim = BOTH_DEATH1;
01706 }
01707 else
01708 {
01709 deathAnim = BOTH_DEATH16;
01710 }
01711 }
01712 else
01713 {
01714 deathAnim = BOTH_DEATH10;
01715 }
01716 break;
01717 case HL_HEAD:
01718 if ( damage <= max_health*0.5 )
01719 {
01720 deathAnim = BOTH_DEATH17;
01721 }
01722 else
01723 {
01724 deathAnim = BOTH_DEATH13;
01725 }
01726 break;
01727 default:
01728 break;
01729 }
01730 }
01731 }
01732
01733
01734 if ( deathAnim == -1 || !BG_HasAnimation( self->localAnimIndex, deathAnim ))
01735 {
01736
01737 deathAnim = BG_PickAnim( self->localAnimIndex, BOTH_DEATH1, BOTH_DEATH25 );
01738 }
01739
01740 return deathAnim;
01741 }
01742
01743 gentity_t *G_GetJediMaster(void)
01744 {
01745 int i = 0;
01746 gentity_t *ent;
01747
01748 while (i < MAX_CLIENTS)
01749 {
01750 ent = &g_entities[i];
01751
01752 if (ent && ent->inuse && ent->client && ent->client->ps.isJediMaster)
01753 {
01754 return ent;
01755 }
01756
01757 i++;
01758 }
01759
01760 return NULL;
01761 }
01762
01763
01764
01765
01766
01767
01768
01769 void G_AlertTeam( gentity_t *victim, gentity_t *attacker, float radius, float soundDist )
01770 {
01771 int radiusEnts[ 128 ];
01772 gentity_t *check;
01773 vec3_t mins, maxs;
01774 int numEnts;
01775 int i;
01776 float distSq, sndDistSq = (soundDist*soundDist);
01777
01778 if ( attacker == NULL || attacker->client == NULL )
01779 return;
01780
01781
01782 for ( i = 0; i < 3; i++ )
01783 {
01784 mins[i] = victim->r.currentOrigin[i] - radius;
01785 maxs[i] = victim->r.currentOrigin[i] + radius;
01786 }
01787
01788
01789 numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 );
01790
01791
01792 for ( i = 0; i < numEnts; i++ )
01793 {
01794 check = &g_entities[radiusEnts[i]];
01795
01796
01797 if ( check->client == NULL )
01798 continue;
01799
01800
01801 if ( check->NPC == NULL )
01802 continue;
01803
01804
01805
01806
01807
01808
01809 if ( check->NPC->scriptFlags & SCF_IGNORE_ALERTS )
01810 continue;
01811
01812
01813 if ( !(check->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
01814 continue;
01815
01816
01817 if ( (check->NPC->scriptFlags&SCF_NO_GROUPS) )
01818 continue;
01819
01820
01821 if ( check == victim )
01822 continue;
01823
01824
01825 if ( check == attacker )
01826 continue;
01827
01828
01829 if ( check->client->playerTeam != victim->client->playerTeam )
01830 continue;
01831
01832
01833 if ( check->health <= 0 )
01834 continue;
01835
01836 if ( check->enemy == NULL )
01837 {
01838 distSq = DistanceSquared( check->r.currentOrigin, victim->r.currentOrigin );
01839 if ( distSq > 16384 && !trap_InPVS( victim->r.currentOrigin, check->r.currentOrigin ) )
01840 {
01841 continue;
01842 }
01843
01844 if ( soundDist <= 0 || distSq > sndDistSq )
01845 {
01846 if ( !InFOV( victim, check, check->NPC->stats.hfov, check->NPC->stats.vfov )
01847 || !NPC_ClearLOS2( check, victim->r.currentOrigin ) )
01848 {
01849 continue;
01850 }
01851 }
01852
01853
01854 G_SetEnemy( check, attacker );
01855 }
01856 }
01857 }
01858
01859
01860
01861
01862
01863
01864
01865 #define DEATH_ALERT_RADIUS 512
01866 #define DEATH_ALERT_SOUND_RADIUS 512
01867
01868 void G_DeathAlert( gentity_t *victim, gentity_t *attacker )
01869 {
01870 G_AlertTeam( victim, attacker, DEATH_ALERT_RADIUS, DEATH_ALERT_SOUND_RADIUS );
01871 }
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882 void DeathFX( gentity_t *ent )
01883 {
01884 vec3_t effectPos, right;
01885 vec3_t defaultDir;
01886
01887 if ( !ent || !ent->client )
01888 return;
01889
01890 VectorSet(defaultDir, 0, 0, 1);
01891
01892
01893 switch(ent->client->NPC_class)
01894 {
01895 case CLASS_MOUSE:
01896 VectorCopy( ent->r.currentOrigin, effectPos );
01897 effectPos[2] -= 20;
01898 G_PlayEffectID( G_EffectIndex("env/small_explode"), effectPos, defaultDir );
01899 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mouse/misc/death1") );
01900 break;
01901
01902 case CLASS_PROBE:
01903 VectorCopy( ent->r.currentOrigin, effectPos );
01904 effectPos[2] += 50;
01905 G_PlayEffectID( G_EffectIndex("explosions/probeexplosion1"), effectPos, defaultDir );
01906 break;
01907
01908 case CLASS_ATST:
01909 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01910 VectorMA( ent->r.currentOrigin, 20, right, effectPos );
01911 effectPos[2] += 180;
01912 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01913 VectorMA( effectPos, -40, right, effectPos );
01914 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01915 break;
01916
01917 case CLASS_SEEKER:
01918 case CLASS_REMOTE:
01919 G_PlayEffectID( G_EffectIndex("env/small_explode"), ent->r.currentOrigin, defaultDir );
01920 break;
01921
01922 case CLASS_GONK:
01923 VectorCopy( ent->r.currentOrigin, effectPos );
01924 effectPos[2] -= 5;
01925
01926 G_Sound( ent, CHAN_AUTO, G_SoundIndex(va("sound/chars/gonk/misc/death%d.wav",Q_irand( 1, 3 ))) );
01927 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01928 break;
01929
01930
01931 case CLASS_R2D2:
01932 VectorCopy( ent->r.currentOrigin, effectPos );
01933 effectPos[2] -= 10;
01934 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01935 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01936 break;
01937
01938 case CLASS_PROTOCOL:
01939 case CLASS_R5D2:
01940 VectorCopy( ent->r.currentOrigin, effectPos );
01941 effectPos[2] -= 10;
01942 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01943 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01944 break;
01945
01946 case CLASS_MARK2:
01947 VectorCopy( ent->r.currentOrigin, effectPos );
01948 effectPos[2] -= 15;
01949 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01950 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01951 break;
01952
01953 case CLASS_INTERROGATOR:
01954 VectorCopy( ent->r.currentOrigin, effectPos );
01955 effectPos[2] -= 15;
01956 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01957 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/interrogator/misc/int_droid_explo") );
01958 break;
01959
01960 case CLASS_MARK1:
01961 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01962 VectorMA( ent->r.currentOrigin, 10, right, effectPos );
01963 effectPos[2] -= 15;
01964 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01965 VectorMA( effectPos, -20, right, effectPos );
01966 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01967 VectorMA( effectPos, -20, right, effectPos );
01968 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01969 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark1/misc/mark1_explo") );
01970 break;
01971
01972 case CLASS_SENTRY:
01973 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/sentry/misc/sentry_explo") );
01974 VectorCopy( ent->r.currentOrigin, effectPos );
01975 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01976 break;
01977
01978 default:
01979 break;
01980
01981 }
01982
01983 }
01984
01985 void G_CheckVictoryScript(gentity_t *self)
01986 {
01987 if ( !G_ActivateBehavior( self, BSET_VICTORY ) )
01988 {
01989 if ( self->NPC && self->s.weapon == WP_SABER )
01990 {
01991 self->NPC->blockedSpeechDebounceTime = 0;
01992 return;
01993 }
01994 if ( self->client && self->client->NPC_class == CLASS_GALAKMECH )
01995 {
01996 self->wait = 1;
01997 TIMER_Set( self, "gloatTime", Q_irand( 5000, 8000 ) );
01998 self->NPC->blockedSpeechDebounceTime = 0;
01999 return;
02000 }
02001
02002 if ( self->NPC && self->NPC->group && self->NPC->group->commander && self->NPC->group->commander->NPC && self->NPC->group->commander->NPC->rank > self->NPC->rank && !Q_irand( 0, 2 ) )
02003 {
02004 self->NPC->group->commander->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02005
02006 }
02007 else if ( self->NPC )
02008 {
02009 self->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02010
02011 }
02012 }
02013 }
02014
02015 void G_AddPowerDuelScore(int team, int score)
02016 {
02017 int i = 0;
02018 gentity_t *check;
02019
02020 while (i < MAX_CLIENTS)
02021 {
02022 check = &g_entities[i];
02023 if (check->inuse && check->client &&
02024 check->client->pers.connected == CON_CONNECTED && !check->client->iAmALoser &&
02025 check->client->ps.stats[STAT_HEALTH] > 0 &&
02026 check->client->sess.sessionTeam != TEAM_SPECTATOR &&
02027 check->client->sess.duelTeam == team)
02028 {
02029 check->client->sess.wins += score;
02030 ClientUserinfoChanged(check->s.number);
02031 }
02032 i++;
02033 }
02034 }
02035
02036 void G_AddPowerDuelLoserScore(int team, int score)
02037 {
02038 int i = 0;
02039 gentity_t *check;
02040
02041 while (i < MAX_CLIENTS)
02042 {
02043 check = &g_entities[i];
02044 if (check->inuse && check->client &&
02045 check->client->pers.connected == CON_CONNECTED &&
02046 (check->client->iAmALoser || (check->client->ps.stats[STAT_HEALTH] <= 0 && check->client->sess.sessionTeam != TEAM_SPECTATOR)) &&
02047 check->client->sess.duelTeam == team)
02048 {
02049 check->client->sess.losses += score;
02050 ClientUserinfoChanged(check->s.number);
02051 }
02052 i++;
02053 }
02054 }
02055
02056
02057
02058
02059
02060
02061 extern stringID_table_t animTable[MAX_ANIMATIONS+1];
02062
02063 extern void AI_DeleteSelfFromGroup( gentity_t *self );
02064 extern void AI_GroupMemberKilled( gentity_t *self );
02065 extern void Boba_FlyStop( gentity_t *self );
02066 extern qboolean Jedi_WaitingAmbush( gentity_t *self );
02067 void CheckExitRules( void );
02068 extern void Rancor_DropVictim( gentity_t *self );
02069
02070 extern qboolean g_dontFrickinCheck;
02071 extern qboolean g_endPDuel;
02072 extern qboolean g_noPDuelCheck;
02073 void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
02074 gentity_t *ent;
02075 int anim;
02076 int contents;
02077 int killer;
02078 int i;
02079 char *killerName, *obit;
02080 qboolean wasJediMaster = qfalse;
02081 int sPMType = 0;
02082
02083 if ( self->client->ps.pm_type == PM_DEAD ) {
02084 return;
02085 }
02086
02087 if ( level.intermissiontime ) {
02088 return;
02089 }
02090
02091
02092 g_dontFrickinCheck = qfalse;
02093
02094 if (g_gametype.integer == GT_POWERDUEL)
02095 {
02096 CheckExitRules();
02097
02098 if ( level.intermissiontime )
02099 {
02100 return;
02101 }
02102 }
02103
02104 if (self->s.eType == ET_NPC &&
02105 self->s.NPC_class == CLASS_VEHICLE &&
02106 self->m_pVehicle &&
02107 !self->m_pVehicle->m_pVehicleInfo->explosionDelay &&
02108 (self->m_pVehicle->m_pPilot || self->m_pVehicle->m_iNumPassengers > 0 || self->m_pVehicle->m_pDroidUnit))
02109 {
02110 gentity_t *murderer = NULL;
02111 gentity_t *killEnt;
02112 int i = 0;
02113
02114 if (self->client->ps.otherKillerTime >= level.time)
02115 {
02116 murderer = &g_entities[self->client->ps.otherKiller];
02117 if (!murderer->inuse || !murderer->client)
02118 {
02119 murderer = NULL;
02120 }
02121 else
02122 {
02123 if (murderer->s.number >= MAX_CLIENTS &&
02124 murderer->s.eType == ET_NPC &&
02125 murderer->s.NPC_class == CLASS_VEHICLE &&
02126 murderer->m_pVehicle &&
02127 murderer->m_pVehicle->m_pPilot)
02128 {
02129 gentity_t *murderPilot = &g_entities[murderer->m_pVehicle->m_pPilot->s.number];
02130 if (murderPilot->inuse && murderPilot->client)
02131 {
02132 murderer = murderPilot;
02133 }
02134 }
02135 }
02136 }
02137 else if (attacker && attacker->inuse && attacker->client)
02138 {
02139 if (attacker->s.number >= MAX_CLIENTS &&
02140 attacker->s.eType == ET_NPC &&
02141 attacker->s.NPC_class == CLASS_VEHICLE &&
02142 attacker->m_pVehicle &&
02143 attacker->m_pVehicle->m_pPilot)
02144 {
02145 murderer = &g_entities[attacker->m_pVehicle->m_pPilot->s.number];
02146 if (murderer->inuse && murderer->client &&murderer->client->ps.otherKillerTime >= level.time)
02147 {
02148 murderer = &g_entities[murderer->client->ps.otherKiller];
02149 if (!murderer->inuse || !murderer->client)
02150 {
02151 murderer = NULL;
02152 }
02153 }
02154 else
02155 {
02156 murderer = NULL;
02157 }
02158 }
02159 else
02160 {
02161 murderer = &g_entities[attacker->s.number];
02162 }
02163 }
02164 else if (self->m_pVehicle->m_pPilot)
02165 {
02166 murderer = (gentity_t *)self->m_pVehicle->m_pPilot;
02167 if (!murderer->inuse || !murderer->client)
02168 {
02169 murderer = NULL;
02170 }
02171 }
02172
02173
02174 if (!murderer)
02175 {
02176 murderer = self;
02177 }
02178
02179 if ( self->m_pVehicle->m_pVehicleInfo->hideRider )
02180 {
02181 killEnt = (gentity_t *)self->m_pVehicle->m_pPilot;
02182 if (killEnt && killEnt->inuse && killEnt->client)
02183 {
02184 G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER);
02185 }
02186 if ( self->m_pVehicle->m_pVehicleInfo )
02187 {
02188
02189 int numPass = self->m_pVehicle->m_iNumPassengers;
02190 for ( i = 0; i < numPass && self->m_pVehicle->m_iNumPassengers; i++ )
02191 {
02192 killEnt = (gentity_t *)self->m_pVehicle->m_ppPassengers[self->m_pVehicle->m_iNumPassengers-1];
02193 if ( killEnt )
02194 {
02195 self->m_pVehicle->m_pVehicleInfo->Eject(self->m_pVehicle, (bgEntity_t *)killEnt, qtrue);
02196 if ( killEnt->inuse && killEnt->client )
02197 {
02198 G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER);
02199 }
02200 }
02201 }
02202 }
02203 }
02204 killEnt = (gentity_t *)self->m_pVehicle->m_pDroidUnit;
02205 if (killEnt && killEnt->inuse && killEnt->client)
02206 {
02207 killEnt->flags &= ~FL_UNDYING;
02208 G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER);
02209 }
02210 }
02211
02212 self->client->ps.emplacedIndex = 0;
02213
02214 G_BreakArm(self, 0);
02215 self->client->ps.saberEntityNum = self->client->saberStoredIndex;
02216
02217 self->client->bodyGrabIndex = ENTITYNUM_NONE;
02218 self->client->bodyGrabTime = 0;
02219
02220 if (self->client->holdingObjectiveItem > 0)
02221 {
02222 gentity_t *objectiveItem = &g_entities[self->client->holdingObjectiveItem];
02223
02224 if (objectiveItem->inuse && objectiveItem->think)
02225 {
02226 objectiveItem->think(objectiveItem);
02227 }
02228 }
02229
02230 if ( (self->client->inSpaceIndex && self->client->inSpaceIndex != ENTITYNUM_NONE) ||
02231 (self->client->ps.eFlags2 & EF2_SHIP_DEATH) )
02232 {
02233 self->client->noCorpse = qtrue;
02234 }
02235
02236 if ( self->client->NPC_class != CLASS_VEHICLE
02237 && self->client->ps.m_iVehicleNum )
02238 {
02239
02240 gentity_t *veh = &g_entities[self->client->ps.m_iVehicleNum];
02241
02242 if (veh->inuse && veh->client && veh->m_pVehicle)
02243 {
02244 veh->m_pVehicle->m_pVehicleInfo->Eject(veh->m_pVehicle, (bgEntity_t *)self, qtrue);
02245
02246 if (veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER)
02247 {
02248 self->client->ps.eFlags2 |= EF2_SHIP_DEATH;
02249
02250
02251 G_SetOrigin(self, veh->client->ps.origin);
02252 VectorCopy(veh->client->ps.origin, self->client->ps.origin);
02253 }
02254 }
02255
02256 switch(self->client->NPC_class)
02257 {
02258 case CLASS_R2D2:
02259 if ( !trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "head" ) )
02260 {
02261 vec3_t up;
02262 AngleVectors( self->r.currentAngles, NULL, NULL, up );
02263 G_PlayEffectID( G_EffectIndex("chunks/r2d2head_veh"), self->r.currentOrigin, up );
02264 }
02265 break;
02266
02267 case CLASS_R5D2:
02268 if ( !trap_G2API_GetSurfaceRenderStatus( self->ghoul2, 0, "head" ) )
02269 {
02270 vec3_t up;
02271 AngleVectors( self->r.currentAngles, NULL, NULL, up );
02272 G_PlayEffectID( G_EffectIndex("chunks/r5d2head_veh"), self->r.currentOrigin, up );
02273 }
02274 break;
02275 }
02276 }
02277
02278 if ( self->NPC )
02279 {
02280 if ( self->client && Jedi_WaitingAmbush( self ) )
02281 {
02282 self->client->noclip = qfalse;
02283 }
02284 NPC_FreeCombatPoint( self->NPC->combatPoint, qfalse );
02285 if ( self->NPC->group )
02286 {
02287
02288 AI_GroupMemberKilled( self );
02289 AI_DeleteSelfFromGroup( self );
02290 }
02291
02292 if ( self->NPC->tempGoal )
02293 {
02294 G_FreeEntity( self->NPC->tempGoal );
02295 self->NPC->tempGoal = NULL;
02296 }
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322 if (0)
02323 {
02324 Boba_FlyStop( self );
02325 }
02326 if ( self->s.NPC_class == CLASS_RANCOR )
02327 {
02328 Rancor_DropVictim( self );
02329 }
02330 }
02331 if ( attacker && attacker->NPC && attacker->NPC->group && attacker->NPC->group->enemy == self )
02332 {
02333 attacker->NPC->group->enemy = NULL;
02334 }
02335
02336
02337
02338 if (self->client->ps.weapon == WP_SABER &&
02339 !self->client->ps.saberHolstered &&
02340 self->client->ps.saberEntityNum)
02341 {
02342 if (!self->client->ps.saberInFlight &&
02343 self->client->saber[0].soundOff)
02344 {
02345 G_Sound(self, CHAN_AUTO, self->client->saber[0].soundOff);
02346 }
02347 if (self->client->saber[1].soundOff &&
02348 self->client->saber[1].model[0])
02349 {
02350 G_Sound(self, CHAN_AUTO, self->client->saber[1].soundOff);
02351 }
02352 }
02353
02354
02355 G_UseTargets( self, self );
02356
02357 if (g_slowmoDuelEnd.integer && (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && attacker && attacker->inuse && attacker->client)
02358 {
02359 if (!gDoSlowMoDuel)
02360 {
02361 gDoSlowMoDuel = qtrue;
02362 gSlowMoDuelTime = level.time;
02363 }
02364 }
02365
02366
02367
02368
02369
02370
02371
02372
02373
02374 Jetpack_Off(self);
02375
02376 self->client->ps.heldByClient = 0;
02377 self->client->beingThrown = 0;
02378 self->client->doingThrow = 0;
02379 BG_ClearRocketLock( &self->client->ps );
02380 self->client->isHacking = 0;
02381 self->client->ps.hackingTime = 0;
02382
02383 if (inflictor && inflictor->activator && !inflictor->client && !attacker->client &&
02384 inflictor->activator->client && inflictor->activator->inuse &&
02385 inflictor->s.weapon == WP_TURRET)
02386 {
02387 attacker = inflictor->activator;
02388 }
02389
02390 if (self->client && self->client->ps.isJediMaster)
02391 {
02392 wasJediMaster = qtrue;
02393 }
02394
02395
02396 G_MuteSound(self->s.number, CHAN_WEAPON);
02397
02398 BlowDetpacks(self);
02399
02400 self->client->ps.fd.forceDeactivateAll = 1;
02401
02402 if ((self == attacker || !attacker->client) &&
02403 (meansOfDeath == MOD_CRUSH || meansOfDeath == MOD_FALLING || meansOfDeath == MOD_TRIGGER_HURT || meansOfDeath == MOD_UNKNOWN) &&
02404 self->client->ps.otherKillerTime > level.time)
02405 {
02406 attacker = &g_entities[self->client->ps.otherKiller];
02407 }
02408
02409
02410 CheckAlmostCapture( self, attacker );
02411
02412 self->client->ps.pm_type = PM_DEAD;
02413 self->client->ps.pm_flags &= ~PMF_STUCK_TO_WALL;
02414
02415 if ( attacker ) {
02416 killer = attacker->s.number;
02417 if ( attacker->client ) {
02418 killerName = attacker->client->pers.netname;
02419 } else {
02420 killerName = "<non-client>";
02421 }
02422 } else {
02423 killer = ENTITYNUM_WORLD;
02424 killerName = "<world>";
02425 }
02426
02427 if ( killer < 0 || killer >= MAX_CLIENTS ) {
02428 killer = ENTITYNUM_WORLD;
02429 killerName = "<world>";
02430 }
02431
02432 if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
02433 obit = "<bad obituary>";
02434 } else {
02435 obit = modNames[ meansOfDeath ];
02436 }
02437
02438 G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n",
02439 killer, self->s.number, meansOfDeath, killerName,
02440 self->client->pers.netname, obit );
02441
02442 if ( g_austrian.integer
02443 && (g_gametype.integer == GT_DUEL)
02444 && level.numPlayingClients >= 2 )
02445 {
02446 int spawnTime = (level.clients[level.sortedClients[0]].respawnTime > level.clients[level.sortedClients[1]].respawnTime) ? level.clients[level.sortedClients[0]].respawnTime : level.clients[level.sortedClients[1]].respawnTime;
02447 G_LogPrintf("Duel Kill Details:\n");
02448 G_LogPrintf("Kill Time: %d\n", level.time-spawnTime );
02449 G_LogPrintf("victim: %s, hits on enemy %d\n", self->client->pers.netname, self->client->ps.persistant[PERS_HITS] );
02450 if ( attacker && attacker->client )
02451 {
02452 G_LogPrintf("killer: %s, hits on enemy %d, health: %d\n", attacker->client->pers.netname, attacker->client->ps.persistant[PERS_HITS], attacker->health );
02453
02454 if ( meansOfDeath == MOD_SABER )
02455 {
02456 G_LogPrintf("killer saber style: %d, killer saber anim %s\n", attacker->client->ps.fd.saberAnimLevel, animTable[(attacker->client->ps.torsoAnim)].name );
02457 }
02458 }
02459 }
02460
02461 G_LogWeaponKill(killer, meansOfDeath);
02462 G_LogWeaponDeath(self->s.number, self->s.weapon);
02463 if (attacker && attacker->client && attacker->inuse)
02464 {
02465 G_LogWeaponFrag(killer, self->s.number);
02466 }
02467
02468
02469 if (self->s.eType != ET_NPC && !g_noPDuelCheck)
02470 {
02471 ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
02472 ent->s.eventParm = meansOfDeath;
02473 ent->s.otherEntityNum = self->s.number;
02474 ent->s.otherEntityNum2 = killer;
02475 ent->r.svFlags = SVF_BROADCAST;
02476 ent->s.isJediMaster = wasJediMaster;
02477 }
02478
02479 self->enemy = attacker;
02480
02481 self->client->ps.persistant[PERS_KILLED]++;
02482
02483 if (self == attacker)
02484 {
02485 self->client->ps.fd.suicides++;
02486 }
02487
02488 if (attacker && attacker->client) {
02489 attacker->client->lastkilled_client = self->s.number;
02490
02491 G_CheckVictoryScript(attacker);
02492
02493 if ( attacker == self || OnSameTeam (self, attacker ) ) {
02494 if (g_gametype.integer == GT_DUEL)
02495 {
02496 int otherClNum = -1;
02497 if (level.sortedClients[0] == self->s.number)
02498 {
02499 otherClNum = level.sortedClients[1];
02500 }
02501 else if (level.sortedClients[1] == self->s.number)
02502 {
02503 otherClNum = level.sortedClients[0];
02504 }
02505
02506 if (otherClNum >= 0 && otherClNum < MAX_CLIENTS &&
02507 g_entities[otherClNum].inuse && g_entities[otherClNum].client &&
02508 otherClNum != attacker->s.number)
02509 {
02510 AddScore( &g_entities[otherClNum], self->r.currentOrigin, 1 );
02511 }
02512 else
02513 {
02514 AddScore( attacker, self->r.currentOrigin, -1 );
02515 }
02516 }
02517 else
02518 {
02519 AddScore( attacker, self->r.currentOrigin, -1 );
02520 }
02521 if (g_gametype.integer == GT_JEDIMASTER)
02522 {
02523 if (self->client && self->client->ps.isJediMaster)
02524 {
02525
02526
02527 ThrowSaberToAttacker(self, NULL);
02528 self->client->ps.isJediMaster = qfalse;
02529 }
02530 }
02531 } else {
02532 if (g_gametype.integer == GT_JEDIMASTER)
02533 {
02534 if ((attacker->client && attacker->client->ps.isJediMaster) ||
02535 (self->client && self->client->ps.isJediMaster))
02536 {
02537 AddScore( attacker, self->r.currentOrigin, 1 );
02538
02539 if (self->client && self->client->ps.isJediMaster)
02540 {
02541 ThrowSaberToAttacker(self, attacker);
02542 self->client->ps.isJediMaster = qfalse;
02543 }
02544 }
02545 else
02546 {
02547 gentity_t *jmEnt = G_GetJediMaster();
02548
02549 if (jmEnt && jmEnt->client)
02550 {
02551 AddScore( jmEnt, self->r.currentOrigin, 1 );
02552 }
02553 }
02554 }
02555 else
02556 {
02557 AddScore( attacker, self->r.currentOrigin, 1 );
02558 }
02559
02560 if( meansOfDeath == MOD_STUN_BATON ) {
02561
02562
02563 attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
02564
02565 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
02566
02567
02568 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
02569 }
02570
02571
02572
02573 if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
02574
02575 attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
02576
02577 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
02578 }
02579 attacker->client->lastKillTime = level.time;
02580
02581 }
02582 } else {
02583 if (self->client && self->client->ps.isJediMaster)
02584 {
02585
02586
02587 ThrowSaberToAttacker(self, NULL);
02588 self->client->ps.isJediMaster = qfalse;
02589 }
02590
02591 if (g_gametype.integer == GT_DUEL)
02592 {
02593 int otherClNum = -1;
02594 if (level.sortedClients[0] == self->s.number)
02595 {
02596 otherClNum = level.sortedClients[1];
02597 }
02598 else if (level.sortedClients[1] == self->s.number)
02599 {
02600 otherClNum = level.sortedClients[0];
02601 }
02602
02603 if (otherClNum >= 0 && otherClNum < MAX_CLIENTS &&
02604 g_entities[otherClNum].inuse && g_entities[otherClNum].client &&
02605 otherClNum != self->s.number)
02606 {
02607 AddScore( &g_entities[otherClNum], self->r.currentOrigin, 1 );
02608 }
02609 else
02610 {
02611 AddScore( self, self->r.currentOrigin, -1 );
02612 }
02613 }
02614 else
02615 {
02616 AddScore( self, self->r.currentOrigin, -1 );
02617 }
02618 }
02619
02620
02621 Team_FragBonuses(self, inflictor, attacker);
02622
02623
02624 if (meansOfDeath == MOD_SUICIDE) {
02625 if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {
02626 Team_ReturnFlag( TEAM_FREE );
02627 self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
02628 }
02629 else if ( self->client->ps.powerups[PW_REDFLAG] ) {
02630 Team_ReturnFlag( TEAM_RED );
02631 self->client->ps.powerups[PW_REDFLAG] = 0;
02632 }
02633 else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {
02634 Team_ReturnFlag( TEAM_BLUE );
02635 self->client->ps.powerups[PW_BLUEFLAG] = 0;
02636 }
02637 }
02638
02639
02640 contents = trap_PointContents( self->r.currentOrigin, -1 );
02641 if ( !( contents & CONTENTS_NODROP ) && !self->client->ps.fallingToDeath) {
02642 if (self->s.eType != ET_NPC)
02643 {
02644 TossClientItems( self );
02645 }
02646 }
02647 else {
02648 if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {
02649 Team_ReturnFlag( TEAM_FREE );
02650 }
02651 else if ( self->client->ps.powerups[PW_REDFLAG] ) {
02652 Team_ReturnFlag( TEAM_RED );
02653 }
02654 else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {
02655 Team_ReturnFlag( TEAM_BLUE );
02656 }
02657 }
02658
02659 if ( MOD_TEAM_CHANGE == meansOfDeath )
02660 {
02661
02662 AddScore( self, self->r.currentOrigin, 1 );
02663 }
02664 else
02665 {
02666 Cmd_Score_f( self );
02667 }
02668
02669
02670
02671 for ( i = 0 ; i < level.maxclients ; i++ ) {
02672 gclient_t *client;
02673
02674 client = &level.clients[i];
02675 if ( client->pers.connected != CON_CONNECTED ) {
02676 continue;
02677 }
02678 if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
02679 continue;
02680 }
02681 if ( client->sess.spectatorClient == self->s.number ) {
02682 Cmd_Score_f( g_entities + i );
02683 }
02684 }
02685
02686 self->takedamage = qtrue;
02687
02688 self->s.weapon = WP_NONE;
02689 self->s.powerups = 0;
02690 if (self->s.eType != ET_NPC)
02691 {
02692 self->r.contents = CONTENTS_CORPSE;
02693 }
02694 self->client->ps.zoomMode = 0;
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705 self->s.loopSound = 0;
02706 self->s.loopIsSoundset = qfalse;
02707
02708 if (self->s.eType != ET_NPC)
02709 {
02710 self->r.maxs[2] = -8;
02711 }
02712
02713
02714
02715 self->client->respawnTime = level.time + 1700;
02716
02717
02718 memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730 {
02731
02732
02733 static int i;
02734
02735 anim = G_PickDeathAnim(self, self->pos1, damage, meansOfDeath, HL_NONE);
02736
02737 if (anim >= 1)
02738 {
02739
02740
02741 if ( self->health <= GIB_HEALTH ) {
02742 self->health = GIB_HEALTH+1;
02743 }
02744
02745 self->client->respawnTime = level.time + 1000;
02746
02747 sPMType = self->client->ps.pm_type;
02748 self->client->ps.pm_type = PM_NORMAL;
02749
02750 if (self->inuse)
02751 {
02752 G_SetAnim(self, NULL, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART, 0);
02753 }
02754
02755 self->client->ps.pm_type = sPMType;
02756
02757 if (meansOfDeath == MOD_SABER || (meansOfDeath == MOD_MELEE && G_HeavyMelee( attacker )) )
02758 {
02759 G_UpdateClientAnims(self, 1.0f);
02760 G_CheckForDismemberment(self, attacker, self->pos1, damage, anim, qfalse);
02761 }
02762 }
02763 else if (self->NPC && self->client && self->client->NPC_class != CLASS_MARK1 &&
02764 self->client->NPC_class != CLASS_VEHICLE)
02765 {
02766 self->think = G_FreeEntity;
02767 self->nextthink = level.time;
02768 }
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778 if (wasJediMaster)
02779 {
02780 G_AddEvent( self, EV_DEATH1 + i, 1 );
02781 }
02782 else
02783 {
02784 G_AddEvent( self, EV_DEATH1 + i, 0 );
02785 }
02786
02787 if (self != attacker)
02788 {
02789 G_DeathAlert( self, attacker );
02790 }
02791
02792
02793 if (!self->NPC)
02794 {
02795 self->die = body_die;
02796 }
02797
02798
02799 self->takedamage = qtrue;
02800
02801
02802 i = ( i + 1 ) % 3;
02803 }
02804
02805 if ( self->NPC )
02806 {
02807 self->NPC->nextBStateThink = level.time;
02808 }
02809
02810 if ( G_ActivateBehavior( self, BSET_DEATH ) )
02811 {
02812
02813 }
02814
02815 if ( self->NPC && (self->NPC->scriptFlags&SCF_FFDEATH) )
02816 {
02817 if ( G_ActivateBehavior( self, BSET_FFDEATH ) )
02818 {
02819
02820 }
02821 G_UseTargets2( self, self, self->target4 );
02822 }
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836 TIMER_Clear2( self );
02837
02838 trap_LinkEntity (self);
02839
02840 if ( self->NPC )
02841 {
02842 self->NPC->timeOfDeath = level.time;
02843 }
02844
02845
02846 DeathFX( self );
02847
02848
02849 if (g_gametype.integer == GT_POWERDUEL && !g_noPDuelCheck)
02850 {
02851 if (self->client->sess.duelTeam == DUELTEAM_LONE)
02852 {
02853 G_AddPowerDuelScore(DUELTEAM_DOUBLE, 1);
02854 G_AddPowerDuelLoserScore(DUELTEAM_LONE, 1);
02855 g_endPDuel = qtrue;
02856 }
02857 else if (self->client->sess.duelTeam == DUELTEAM_DOUBLE)
02858 {
02859 int i = 0;
02860 gentity_t *check;
02861 qboolean heLives = qfalse;
02862
02863 while (i < MAX_CLIENTS)
02864 {
02865 check = &g_entities[i];
02866 if (check->inuse && check->client && check->s.number != self->s.number &&
02867 check->client->pers.connected == CON_CONNECTED && !check->client->iAmALoser &&
02868 check->client->ps.stats[STAT_HEALTH] > 0 &&
02869 check->client->sess.sessionTeam != TEAM_SPECTATOR &&
02870 check->client->sess.duelTeam == DUELTEAM_DOUBLE)
02871 {
02872 heLives = qtrue;
02873 break;
02874 }
02875 i++;
02876 }
02877
02878 if (!heLives)
02879 {
02880 G_AddPowerDuelScore(DUELTEAM_LONE, 1);
02881 G_AddPowerDuelLoserScore(DUELTEAM_DOUBLE, 1);
02882 g_endPDuel = qtrue;
02883 }
02884 }
02885 }
02886 }
02887
02888
02889
02890
02891
02892
02893
02894 int CheckArmor (gentity_t *ent, int damage, int dflags)
02895 {
02896 gclient_t *client;
02897 int save;
02898 int count;
02899
02900 if (!damage)
02901 return 0;
02902
02903 client = ent->client;
02904
02905 if (!client)
02906 return 0;
02907
02908 if (dflags & DAMAGE_NO_ARMOR)
02909 return 0;
02910
02911 if ( client->NPC_class == CLASS_VEHICLE
02912 && ent->m_pVehicle
02913 && ent->client->ps.electrifyTime > level.time )
02914 {
02915 return 0;
02916 }
02917
02918 count = client->ps.stats[STAT_ARMOR];
02919
02920 if (dflags & DAMAGE_HALF_ABSORB)
02921 {
02922 save = ceil( damage * ARMOR_PROTECTION );
02923 }
02924 else
02925 {
02926 save = damage;
02927 }
02928
02929
02930 if (save >= count)
02931 save = count;
02932
02933 if (!save)
02934 return 0;
02935
02936 if (dflags & DAMAGE_HALF_ARMOR_REDUCTION)
02937 {
02938 client->ps.stats[STAT_ARMOR] -= (int)(save*ARMOR_REDUCTION_FACTOR);
02939 }
02940 else
02941 {
02942 client->ps.stats[STAT_ARMOR] -= save;
02943 }
02944
02945 return save;
02946 }
02947
02948
02949 void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback )
02950 {
02951 vec3_t kvel;
02952 float mass;
02953
02954 if ( targ->physicsBounce > 0 )
02955 mass = targ->physicsBounce;
02956 else
02957 mass = 200;
02958
02959 if ( g_gravity.value > 0 )
02960 {
02961 VectorScale( newDir, g_knockback.value * (float)knockback / mass * 0.8, kvel );
02962 kvel[2] = newDir[2] * g_knockback.value * (float)knockback / mass * 1.5;
02963 }
02964 else
02965 {
02966 VectorScale( newDir, g_knockback.value * (float)knockback / mass, kvel );
02967 }
02968
02969 if ( targ->client )
02970 {
02971 VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
02972 }
02973 else if ( targ->s.pos.trType != TR_STATIONARY && targ->s.pos.trType != TR_LINEAR_STOP && targ->s.pos.trType != TR_NONLINEAR_STOP )
02974 {
02975 VectorAdd( targ->s.pos.trDelta, kvel, targ->s.pos.trDelta );
02976 VectorCopy( targ->r.currentOrigin, targ->s.pos.trBase );
02977 targ->s.pos.trTime = level.time;
02978 }
02979
02980
02981
02982 if ( targ->client && !targ->client->ps.pm_time )
02983 {
02984 int t;
02985
02986 t = knockback * 2;
02987 if ( t < 50 ) {
02988 t = 50;
02989 }
02990 if ( t > 200 ) {
02991 t = 200;
02992 }
02993 targ->client->ps.pm_time = t;
02994 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
02995 }
02996 }
02997
02998
02999
03000
03001
03002
03003 int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
03004 float b, c, d, t;
03005
03006
03007
03008
03009
03010
03011
03012 VectorNormalize(dir);
03013 b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
03014 c = (point[0] - origin[0]) * (point[0] - origin[0]) +
03015 (point[1] - origin[1]) * (point[1] - origin[1]) +
03016 (point[2] - origin[2]) * (point[2] - origin[2]) -
03017 radius * radius;
03018
03019 d = b * b - 4 * c;
03020 if (d > 0) {
03021 t = (- b + sqrt(d)) / 2;
03022 VectorMA(point, t, dir, intersections[0]);
03023 t = (- b - sqrt(d)) / 2;
03024 VectorMA(point, t, dir, intersections[1]);
03025 return 2;
03026 }
03027 else if (d == 0) {
03028 t = (- b ) / 2;
03029 VectorMA(point, t, dir, intersections[0]);
03030 return 1;
03031 }
03032 return 0;
03033 }
03034
03035
03036
03037
03038
03039
03040 char *hitLocName[HL_MAX] =
03041 {
03042 "none",
03043 "right foot",
03044 "left foot",
03045 "right leg",
03046 "left leg",
03047 "waist",
03048 "back right shoulder",
03049 "back left shoulder",
03050 "back",
03051 "front right shouler",
03052 "front left shoulder",
03053 "chest",
03054 "right arm",
03055 "left arm",
03056 "right hand",
03057 "left hand",
03058 "head",
03059 "generic1",
03060 "generic2",
03061 "generic3",
03062 "generic4",
03063 "generic5",
03064 "generic6"
03065 };
03066
03067 void G_GetDismemberLoc(gentity_t *self, vec3_t boltPoint, int limbType)
03068 {
03069 vec3_t fwd, right, up;
03070
03071 AngleVectors(self->r.currentAngles, fwd, right, up);
03072
03073 VectorCopy(self->r.currentOrigin, boltPoint);
03074
03075 switch (limbType)
03076 {
03077 case G2_MODELPART_HEAD:
03078 boltPoint[0] += up[0]*24;
03079 boltPoint[1] += up[1]*24;
03080 boltPoint[2] += up[2]*24;
03081 break;
03082 case G2_MODELPART_WAIST:
03083 boltPoint[0] += up[0]*4;
03084 boltPoint[1] += up[1]*4;
03085 boltPoint[2] += up[2]*4;
03086 break;
03087 case G2_MODELPART_LARM:
03088 boltPoint[0] += up[0]*18;
03089 boltPoint[1] += up[1]*18;
03090 boltPoint[2] += up[2]*18;
03091
03092 boltPoint[0] -= right[0]*10;
03093 boltPoint[1] -= right[1]*10;
03094 boltPoint[2] -= right[2]*10;
03095 break;
03096 case G2_MODELPART_RARM:
03097 boltPoint[0] += up[0]*18;
03098 boltPoint[1] += up[1]*18;
03099 boltPoint[2] += up[2]*18;
03100
03101 boltPoint[0] += right[0]*10;
03102 boltPoint[1] += right[1]*10;
03103 boltPoint[2] += right[2]*10;
03104 break;
03105 case G2_MODELPART_RHAND:
03106 boltPoint[0] += up[0]*8;
03107 boltPoint[1] += up[1]*8;
03108 boltPoint[2] += up[2]*8;
03109
03110 boltPoint[0] += right[0]*10;
03111 boltPoint[1] += right[1]*10;
03112 boltPoint[2] += right[2]*10;
03113 break;
03114 case G2_MODELPART_LLEG:
03115 boltPoint[0] -= up[0]*4;
03116 boltPoint[1] -= up[1]*4;
03117 boltPoint[2] -= up[2]*4;
03118
03119 boltPoint[0] -= right[0]*10;
03120 boltPoint[1] -= right[1]*10;
03121 boltPoint[2] -= right[2]*10;
03122 break;
03123 case G2_MODELPART_RLEG:
03124 boltPoint[0] -= up[0]*4;
03125 boltPoint[1] -= up[1]*4;
03126 boltPoint[2] -= up[2]*4;
03127
03128 boltPoint[0] += right[0]*10;
03129 boltPoint[1] += right[1]*10;
03130 boltPoint[2] += right[2]*10;
03131 break;
03132 default:
03133 break;
03134 }
03135
03136 return;
03137 }
03138
03139 void G_GetDismemberBolt(gentity_t *self, vec3_t boltPoint, int limbType)
03140 {
03141 int useBolt = self->genericValue5;
03142 vec3_t properOrigin, properAngles, addVel;
03143
03144 mdxaBone_t boltMatrix;
03145 float fVSpeed = 0;
03146 char *rotateBone = NULL;
03147
03148 switch (limbType)
03149 {
03150 case G2_MODELPART_HEAD:
03151 rotateBone = "cranium";
03152 break;
03153 case G2_MODELPART_WAIST:
03154 if (self->localAnimIndex <= 1)
03155 {
03156 rotateBone = "thoracic";
03157 }
03158 else
03159 {
03160 rotateBone = "pelvis";
03161 }
03162 break;
03163 case G2_MODELPART_LARM:
03164 rotateBone = "lradius";
03165 break;
03166 case G2_MODELPART_RARM:
03167 rotateBone = "rradius";
03168 break;
03169 case G2_MODELPART_RHAND:
03170 rotateBone = "rhand";
03171 break;
03172 case G2_MODELPART_LLEG:
03173 rotateBone = "ltibia";
03174 break;
03175 case G2_MODELPART_RLEG:
03176 rotateBone = "rtibia";
03177 break;
03178 default:
03179 rotateBone = "rtibia";
03180 break;
03181 }
03182
03183 useBolt = trap_G2API_AddBolt(self->ghoul2, 0, rotateBone);
03184
03185 VectorCopy(self->client->ps.origin, properOrigin);
03186 VectorCopy(self->client->ps.viewangles, properAngles);
03187
03188
03189 VectorCopy(self->client->ps.velocity, addVel);
03190 VectorNormalize(addVel);
03191
03192 if (self->client->ps.velocity[0] < 0)
03193 {
03194 fVSpeed += (-self->client->ps.velocity[0]);
03195 }
03196 else
03197 {
03198 fVSpeed += self->client->ps.velocity[0];
03199 }
03200 if (self->client->ps.velocity[1] < 0)
03201 {
03202 fVSpeed += (-self->client->ps.velocity[1]);
03203 }
03204 else
03205 {
03206 fVSpeed += self->client->ps.velocity[1];
03207 }
03208 if (self->client->ps.velocity[2] < 0)
03209 {
03210 fVSpeed += (-self->client->ps.velocity[2]);
03211 }
03212 else
03213 {
03214 fVSpeed += self->client->ps.velocity[2];
03215 }
03216
03217 fVSpeed *= 0.08;
03218
03219 properOrigin[0] += addVel[0]*fVSpeed;
03220 properOrigin[1] += addVel[1]*fVSpeed;
03221 properOrigin[2] += addVel[2]*fVSpeed;
03222
03223 properAngles[0] = 0;
03224 properAngles[1] = self->client->ps.viewangles[YAW];
03225 properAngles[2] = 0;
03226
03227 trap_G2API_GetBoltMatrix(self->ghoul2, 0, useBolt, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03228
03229 boltPoint[0] = boltMatrix.matrix[0][3];
03230 boltPoint[1] = boltMatrix.matrix[1][3];
03231 boltPoint[2] = boltMatrix.matrix[2][3];
03232
03233 trap_G2API_GetBoltMatrix(self->ghoul2, 1, 0, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03234
03235 if (self->client && limbType == G2_MODELPART_RHAND)
03236 {
03237 vec3_t boltAngles;
03238 gentity_t *te;
03239
03240 boltAngles[0] = -boltMatrix.matrix[0][1];
03241 boltAngles[1] = -boltMatrix.matrix[1][1];
03242 boltAngles[2] = -boltMatrix.matrix[2][1];
03243
03244 te = G_TempEntity( boltPoint, EV_SABER_HIT );
03245 te->s.otherEntityNum = self->s.number;
03246 te->s.otherEntityNum2 = ENTITYNUM_NONE;
03247 te->s.weapon = 0;
03248 te->s.legsAnim = 0;
03249
03250 VectorCopy(boltPoint, te->s.origin);
03251 VectorCopy(boltAngles, te->s.angles);
03252
03253 if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
03254 {
03255 te->s.angles[1] = 1;
03256 }
03257
03258 te->s.eventParm = 16;
03259 }
03260 }
03261
03262 void LimbTouch( gentity_t *self, gentity_t *other, trace_t *trace )
03263 {
03264 }
03265
03266 void LimbThink( gentity_t *ent )
03267 {
03268 float gravity = 3.0f;
03269 float mass = 0.09f;
03270 float bounce = 1.3f;
03271
03272 switch (ent->s.modelGhoul2)
03273 {
03274 case G2_MODELPART_HEAD:
03275 mass = 0.08f;
03276 bounce = 1.4f;
03277 break;
03278 case G2_MODELPART_WAIST:
03279 mass = 0.1f;
03280 bounce = 1.2f;
03281 break;
03282 case G2_MODELPART_LARM:
03283 case G2_MODELPART_RARM:
03284 case G2_MODELPART_RHAND:
03285 case G2_MODELPART_LLEG:
03286 case G2_MODELPART_RLEG:
03287 default:
03288 break;
03289 }
03290
03291 if (ent->speed < level.time)
03292 {
03293 ent->think = G_FreeEntity;
03294 ent->nextthink = level.time;
03295 return;
03296 }
03297
03298 if (ent->genericValue5 <= level.time)
03299 {
03300 G_RunExPhys(ent, gravity, mass, bounce, qtrue, NULL, 0);
03301 ent->genericValue5 = level.time + 50;
03302 }
03303
03304 ent->nextthink = level.time;
03305 }
03306
03307 #include "../namespace_begin.h"
03308 extern qboolean BG_GetRootSurfNameWithVariant( void *ghoul2, const char *rootSurfName, char *returnSurfName, int returnSize );
03309 #include "../namespace_end.h"
03310
03311 void G_Dismember( gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath )
03312 {
03313 vec3_t newPoint, dir, vel;
03314 gentity_t *limb;
03315 char limbName[MAX_QPATH];
03316 char stubName[MAX_QPATH];
03317 char stubCapName[MAX_QPATH];
03318
03319 if (limbType == G2_MODELPART_HEAD)
03320 {
03321 Q_strncpyz( limbName , "head", sizeof( limbName ) );
03322 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
03323 }
03324 else if (limbType == G2_MODELPART_WAIST)
03325 {
03326 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
03327 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
03328 }
03329 else if (limbType == G2_MODELPART_LARM)
03330 {
03331 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_arm", limbName, sizeof(limbName) );
03332 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03333 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
03334 }
03335 else if (limbType == G2_MODELPART_RARM)
03336 {
03337 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", limbName, sizeof(limbName) );
03338 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03339 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
03340 }
03341 else if (limbType == G2_MODELPART_RHAND)
03342 {
03343 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_hand", limbName, sizeof(limbName) );
03344 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", stubName, sizeof(stubName) );
03345 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
03346 }
03347 else if (limbType == G2_MODELPART_LLEG)
03348 {
03349 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_leg", limbName, sizeof(limbName) );
03350 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03351 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
03352 }
03353 else if (limbType == G2_MODELPART_RLEG)
03354 {
03355 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03356 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03357 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03358 }
03359 else
03360 {
03361 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03362 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03363 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03364 }
03365
03366 if (ent->ghoul2 && limbName && trap_G2API_GetSurfaceRenderStatus(ent->ghoul2, 0, limbName))
03367 {
03368 return;
03369 }
03370
03371 VectorCopy( point, newPoint );
03372 limb = G_Spawn();
03373 limb->classname = "playerlimb";
03374
03375
03376
03377
03378
03379
03380
03381
03382 G_SetOrigin( limb, newPoint );
03383 VectorCopy( newPoint, limb->s.pos.trBase );
03384 limb->think = LimbThink;
03385 limb->touch = LimbTouch;
03386 limb->speed = level.time + Q_irand(8000, 16000);
03387 limb->nextthink = level.time + FRAMETIME;
03388
03389 limb->r.svFlags = SVF_USE_CURRENT_ORIGIN;
03390 limb->clipmask = MASK_SOLID;
03391 limb->r.contents = CONTENTS_TRIGGER;
03392 limb->physicsObject = qtrue;
03393 VectorSet( limb->r.mins, -6.0f, -6.0f, -3.0f );
03394 VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f );
03395
03396 limb->s.g2radius = 200;
03397
03398 limb->s.eType = ET_GENERAL;
03399 limb->s.weapon = G2_MODEL_PART;
03400 limb->s.modelGhoul2 = limbType;
03401 limb->s.modelindex = ent->s.number;
03402 if (!ent->client)
03403 {
03404 limb->s.modelindex = -1;
03405 limb->s.otherEntityNum2 = ent->s.number;
03406 }
03407
03408 VectorClear(limb->s.apos.trDelta);
03409
03410 if (ent->client)
03411 {
03412 VectorCopy(ent->client->ps.viewangles, limb->r.currentAngles);
03413 VectorCopy(ent->client->ps.viewangles, limb->s.apos.trBase);
03414 }
03415 else
03416 {
03417 VectorCopy(ent->r.currentAngles, limb->r.currentAngles);
03418 VectorCopy(ent->r.currentAngles, limb->s.apos.trBase);
03419 }
03420
03421
03422 limb->epGravFactor = 0;
03423 VectorClear(limb->epVelocity);
03424 VectorSubtract( point, ent->r.currentOrigin, dir );
03425 VectorNormalize( dir );
03426 if (ent->client)
03427 {
03428 VectorCopy(ent->client->ps.velocity, vel);
03429 }
03430 else
03431 {
03432 VectorCopy(ent->s.pos.trDelta, vel);
03433 }
03434 VectorMA( vel, 80, dir, limb->epVelocity );
03435
03436
03437 if (limbType == G2_MODELPART_HEAD ||
03438 limbType == G2_MODELPART_WAIST)
03439 {
03440 limb->epVelocity[2] += 10;
03441 }
03442
03443 if (enemy && enemy->client && ent && ent != enemy && ent->s.number != enemy->s.number &&
03444 enemy->client->ps.weapon == WP_SABER && enemy->client->olderIsValid &&
03445 (level.time - enemy->client->lastSaberStorageTime) < 200)
03446 {
03447 vec3_t dif;
03448 float totalDistance;
03449 const float distScale = 1.2f;
03450
03451
03452
03453 VectorScale(limb->epVelocity, 0.4f, limb->epVelocity);
03454
03455 VectorSubtract(enemy->client->lastSaberBase_Always, enemy->client->olderSaberBase, dif);
03456 totalDistance = VectorNormalize(dif);
03457
03458 VectorScale(dif, totalDistance*distScale, dif);
03459 VectorAdd(limb->epVelocity, dif, limb->epVelocity);
03460
03461 if (ent->client && (ent->client->ps.torsoTimer > 0 || !BG_InDeathAnim(ent->client->ps.torsoAnim)))
03462 {
03463 vec3_t preVel;
03464
03465 VectorCopy(limb->epVelocity, preVel);
03466 preVel[2] = 0;
03467 totalDistance = VectorNormalize(preVel);
03468
03469 if (totalDistance < 40.0f)
03470 {
03471 float mAmt = 40.0f;
03472
03473 limb->epVelocity[0] = preVel[0]*mAmt;
03474 limb->epVelocity[1] = preVel[1]*mAmt;
03475 }
03476 }
03477 else if (ent->client)
03478 {
03479 VectorScale(limb->epVelocity, 0.3f, limb->epVelocity);
03480 }
03481 }
03482
03483 if (ent->s.eType == ET_NPC && ent->ghoul2 && limbName && stubCapName)
03484 {
03485 trap_G2API_SetSurfaceOnOff(ent->ghoul2, limbName, 0x00000100);
03486 trap_G2API_SetSurfaceOnOff(ent->ghoul2, stubCapName, 0);
03487 }
03488
03489 limb->s.customRGBA[0] = ent->s.customRGBA[0];
03490 limb->s.customRGBA[1] = ent->s.customRGBA[1];
03491 limb->s.customRGBA[2] = ent->s.customRGBA[2];
03492 limb->s.customRGBA[3] = ent->s.customRGBA[3];
03493
03494 trap_LinkEntity( limb );
03495 }
03496
03497 void DismembermentTest(gentity_t *self)
03498 {
03499 int sect = G2_MODELPART_HEAD;
03500 vec3_t boltPoint;
03501
03502 while (sect <= G2_MODELPART_RLEG)
03503 {
03504 G_GetDismemberBolt(self, boltPoint, sect);
03505 G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03506 sect++;
03507 }
03508 }
03509
03510 void DismembermentByNum(gentity_t *self, int num)
03511 {
03512 int sect = G2_MODELPART_HEAD;
03513 vec3_t boltPoint;
03514
03515 switch (num)
03516 {
03517 case 0:
03518 sect = G2_MODELPART_HEAD;
03519 break;
03520 case 1:
03521 sect = G2_MODELPART_WAIST;
03522 break;
03523 case 2:
03524 sect = G2_MODELPART_LARM;
03525 break;
03526 case 3:
03527 sect = G2_MODELPART_RARM;
03528 break;
03529 case 4:
03530 sect = G2_MODELPART_RHAND;
03531 break;
03532 case 5:
03533 sect = G2_MODELPART_LLEG;
03534 break;
03535 case 6:
03536 sect = G2_MODELPART_RLEG;
03537 break;
03538 default:
03539 break;
03540 }
03541
03542 G_GetDismemberBolt(self, boltPoint, sect);
03543 G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03544 }
03545
03546 int G_GetHitQuad( gentity_t *self, vec3_t hitloc )
03547 {
03548 vec3_t diff, fwdangles={0,0,0}, right;
03549 vec3_t clEye;
03550 float rightdot;
03551 float zdiff;
03552 int hitLoc = gPainHitLoc;
03553
03554 if (self->client)
03555 {
03556 VectorCopy(self->client->ps.origin, clEye);
03557 clEye[2] += self->client->ps.viewheight;
03558 }
03559 else
03560 {
03561 VectorCopy(self->s.pos.trBase, clEye);
03562 clEye[2] += 16;
03563 }
03564
03565 VectorSubtract( hitloc, clEye, diff );
03566 diff[2] = 0;
03567 VectorNormalize( diff );
03568
03569 if (self->client)
03570 {
03571 fwdangles[1] = self->client->ps.viewangles[1];
03572 }
03573 else
03574 {
03575 fwdangles[1] = self->s.apos.trBase[1];
03576 }
03577
03578 AngleVectors( fwdangles, NULL, right, NULL );
03579
03580 rightdot = DotProduct(right, diff);
03581 zdiff = hitloc[2] - clEye[2];
03582
03583 if ( zdiff > 0 )
03584 {
03585 if ( rightdot > 0.3 )
03586 {
03587 hitLoc = G2_MODELPART_RARM;
03588 }
03589 else if ( rightdot < -0.3 )
03590 {
03591 hitLoc = G2_MODELPART_LARM;
03592 }
03593 else
03594 {
03595 hitLoc = G2_MODELPART_HEAD;
03596 }
03597 }
03598 else if ( zdiff > -20 )
03599 {
03600 if ( rightdot > 0.1 )
03601 {
03602 hitLoc = G2_MODELPART_RARM;
03603 }
03604 else if ( rightdot < -0.1 )
03605 {
03606 hitLoc = G2_MODELPART_LARM;
03607 }
03608 else
03609 {
03610 hitLoc = G2_MODELPART_HEAD;
03611 }
03612 }
03613 else
03614 {
03615 if ( rightdot >= 0 )
03616 {
03617 hitLoc = G2_MODELPART_RLEG;
03618 }
03619 else
03620 {
03621 hitLoc = G2_MODELPART_LLEG;
03622 }
03623 }
03624
03625 return hitLoc;
03626 }
03627
03628 int gGAvoidDismember = 0;
03629
03630 void UpdateClientRenderBolts(gentity_t *self, vec3_t renderOrigin, vec3_t renderAngles);
03631
03632 qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod )
03633 {
03634 qboolean dismember = qfalse;
03635 int actualTime;
03636 int kneeLBolt = -1;
03637 int kneeRBolt = -1;
03638 int handRBolt = -1;
03639 int handLBolt = -1;
03640 int footRBolt = -1;
03641 int footLBolt = -1;
03642
03643 *hitLoc = HL_NONE;
03644
03645 if ( !surfName || !surfName[0] )
03646 {
03647 return qfalse;
03648 }
03649
03650 if( !ent->client )
03651 {
03652 return qfalse;
03653 }
03654
03655 if (!point)
03656 {
03657 return qfalse;
03658 }
03659
03660 if ( ent->client
03661 && ( ent->client->NPC_class == CLASS_R2D2
03662 || ent->client->NPC_class == CLASS_R2D2
03663 || ent->client->NPC_class == CLASS_GONK
03664 || ent->client->NPC_class == CLASS_MOUSE
03665 || ent->client->NPC_class == CLASS_SENTRY
03666 || ent->client->NPC_class == CLASS_INTERROGATOR
03667 || ent->client->NPC_class == CLASS_SENTRY
03668 || ent->client->NPC_class == CLASS_PROBE ) )
03669 {
03670 return qfalse;
03671 }
03672
03673 if (ent->localAnimIndex <= 1)
03674 {
03675 handLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
03676 handRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
03677 kneeLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_l_knee");
03678 kneeRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_r_knee");
03679 footLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
03680 footRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
03681 }
03682
03683 if ( ent->client && (ent->client->NPC_class == CLASS_ATST) )
03684 {
03685
03686
03687
03688 if (!Q_stricmp("head_light_blaster_cann",surfName))
03689 {
03690 *hitLoc = HL_ARM_LT;
03691 }
03692 else if (!Q_stricmp("head_concussion_charger",surfName))
03693 {
03694 *hitLoc = HL_ARM_RT;
03695 }
03696 return(qfalse);
03697 }
03698 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK1) )
03699 {
03700 if (!Q_stricmp("l_arm",surfName))
03701 {
03702 *hitLoc = HL_ARM_LT;
03703 }
03704 else if (!Q_stricmp("r_arm",surfName))
03705 {
03706 *hitLoc = HL_ARM_RT;
03707 }
03708 else if (!Q_stricmp("torso_front",surfName))
03709 {
03710 *hitLoc = HL_CHEST;
03711 }
03712 else if (!Q_stricmp("torso_tube1",surfName))
03713 {
03714 *hitLoc = HL_GENERIC1;
03715 }
03716 else if (!Q_stricmp("torso_tube2",surfName))
03717 {
03718 *hitLoc = HL_GENERIC2;
03719 }
03720 else if (!Q_stricmp("torso_tube3",surfName))
03721 {
03722 *hitLoc = HL_GENERIC3;
03723 }
03724 else if (!Q_stricmp("torso_tube4",surfName))
03725 {
03726 *hitLoc = HL_GENERIC4;
03727 }
03728 else if (!Q_stricmp("torso_tube5",surfName))
03729 {
03730 *hitLoc = HL_GENERIC5;
03731 }
03732 else if (!Q_stricmp("torso_tube6",surfName))
03733 {
03734 *hitLoc = HL_GENERIC6;
03735 }
03736 return(qfalse);
03737 }
03738 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK2) )
03739 {
03740 if (!Q_stricmp("torso_canister1",surfName))
03741 {
03742 *hitLoc = HL_GENERIC1;
03743 }
03744 else if (!Q_stricmp("torso_canister2",surfName))
03745 {
03746 *hitLoc = HL_GENERIC2;
03747 }
03748 else if (!Q_stricmp("torso_canister3",surfName))
03749 {
03750 *hitLoc = HL_GENERIC3;
03751 }
03752 return(qfalse);
03753 }
03754 else if ( ent->client && (ent->client->NPC_class == CLASS_GALAKMECH) )
03755 {
03756 if (!Q_stricmp("torso_antenna",surfName)||!Q_stricmp("torso_antenna_base",surfName))
03757 {
03758 *hitLoc = HL_GENERIC1;
03759 }
03760 else if (!Q_stricmp("torso_shield",surfName))
03761 {
03762 *hitLoc = HL_GENERIC2;
03763 }
03764 else
03765 {
03766 *hitLoc = HL_CHEST;
03767 }
03768 return(qfalse);
03769 }
03770
03771
03772
03773
03774
03775 actualTime = level.time;
03776 if ( !Q_strncmp( "hips", surfName, 4 ) )
03777 {
03778 *hitLoc = HL_WAIST;
03779 if ( ent->client != NULL && ent->ghoul2 )
03780 {
03781 mdxaBone_t boltMatrix;
03782 vec3_t tagOrg, angles;
03783
03784 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03785 if (kneeLBolt>=0)
03786 {
03787 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeLBolt,
03788 &boltMatrix, angles, ent->r.currentOrigin,
03789 actualTime, NULL, ent->modelScale );
03790 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03791 if ( DistanceSquared( point, tagOrg ) < 100 )
03792 {
03793 *hitLoc = HL_LEG_LT;
03794 }
03795 }
03796 if (*hitLoc == HL_WAIST)
03797 {
03798 if (kneeRBolt>=0)
03799 {
03800 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeRBolt,
03801 &boltMatrix, angles, ent->r.currentOrigin,
03802 actualTime, NULL, ent->modelScale );
03803 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03804 if ( DistanceSquared( point, tagOrg ) < 100 )
03805 {
03806 *hitLoc = HL_LEG_RT;
03807 }
03808 }
03809 }
03810 }
03811 }
03812 else if ( !Q_strncmp( "torso", surfName, 5 ) )
03813 {
03814 if ( !ent->client )
03815 {
03816 *hitLoc = HL_CHEST;
03817 }
03818 else
03819 {
03820 vec3_t t_fwd, t_rt, t_up, dirToImpact;
03821 float frontSide, rightSide, upSide;
03822 AngleVectors( ent->client->renderInfo.torsoAngles, t_fwd, t_rt, t_up );
03823
03824 if (ent->client->renderInfo.boltValidityTime != level.time)
03825 {
03826 vec3_t renderAng;
03827
03828 renderAng[0] = 0;
03829 renderAng[1] = ent->client->ps.viewangles[YAW];
03830 renderAng[2] = 0;
03831
03832 UpdateClientRenderBolts(ent, ent->client->ps.origin, renderAng);
03833 }
03834
03835 VectorSubtract( point, ent->client->renderInfo.torsoPoint, dirToImpact );
03836 frontSide = DotProduct( t_fwd, dirToImpact );
03837 rightSide = DotProduct( t_rt, dirToImpact );
03838 upSide = DotProduct( t_up, dirToImpact );
03839 if ( upSide < -10 )
03840 {
03841 *hitLoc = HL_WAIST;
03842 }
03843 else
03844 {
03845 if ( rightSide > 4 )
03846 {
03847 *hitLoc = HL_ARM_RT;
03848 }
03849 else if ( rightSide < -4 )
03850 {
03851 *hitLoc = HL_ARM_LT;
03852 }
03853 else if ( rightSide > 2 )
03854 {
03855 if ( frontSide > 0 )
03856 {
03857 *hitLoc = HL_CHEST_RT;
03858 }
03859 else
03860 {
03861 *hitLoc = HL_BACK_RT;
03862 }
03863 }
03864 else if ( rightSide < -2 )
03865 {
03866 if ( frontSide > 0 )
03867 {
03868 *hitLoc = HL_CHEST_LT;
03869 }
03870 else
03871 {
03872 *hitLoc = HL_BACK_LT;
03873 }
03874 }
03875 else if ( upSide > -3 && mod == MOD_SABER )
03876 {
03877 *hitLoc = HL_HEAD;
03878 }
03879 else if ( frontSide > 0 )
03880 {
03881 *hitLoc = HL_CHEST;
03882 }
03883 else
03884 {
03885 *hitLoc = HL_BACK;
03886 }
03887 }
03888 }
03889 }
03890 else if ( !Q_strncmp( "head", surfName, 4 ) )
03891 {
03892 *hitLoc = HL_HEAD;
03893 }
03894 else if ( !Q_strncmp( "r_arm", surfName, 5 ) )
03895 {
03896 *hitLoc = HL_ARM_RT;
03897 if ( ent->client != NULL && ent->ghoul2 )
03898 {
03899 mdxaBone_t boltMatrix;
03900 vec3_t tagOrg, angles;
03901
03902 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03903 if (handRBolt>=0)
03904 {
03905 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handRBolt,
03906 &boltMatrix, angles, ent->r.currentOrigin,
03907 actualTime, NULL, ent->modelScale );
03908 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03909 if ( DistanceSquared( point, tagOrg ) < 256 )
03910 {
03911 *hitLoc = HL_HAND_RT;
03912 }
03913 }
03914 }
03915 }
03916 else if ( !Q_strncmp( "l_arm", surfName, 5 ) )
03917 {
03918 *hitLoc = HL_ARM_LT;
03919 if ( ent->client != NULL && ent->ghoul2 )
03920 {
03921 mdxaBone_t boltMatrix;
03922 vec3_t tagOrg, angles;
03923
03924 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03925 if (handLBolt>=0)
03926 {
03927 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handLBolt,
03928 &boltMatrix, angles, ent->r.currentOrigin,
03929 actualTime, NULL, ent->modelScale );
03930 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03931 if ( DistanceSquared( point, tagOrg ) < 256 )
03932 {
03933 *hitLoc = HL_HAND_LT;
03934 }
03935 }
03936 }
03937 }
03938 else if ( !Q_strncmp( "r_leg", surfName, 5 ) )
03939 {
03940 *hitLoc = HL_LEG_RT;
03941 if ( ent->client != NULL && ent->ghoul2 )
03942 {
03943 mdxaBone_t boltMatrix;
03944 vec3_t tagOrg, angles;
03945
03946 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03947 if (footRBolt>=0)
03948 {
03949 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footRBolt,
03950 &boltMatrix, angles, ent->r.currentOrigin,
03951 actualTime, NULL, ent->modelScale );
03952 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03953 if ( DistanceSquared( point, tagOrg ) < 100 )
03954 {
03955 *hitLoc = HL_FOOT_RT;
03956 }
03957 }
03958 }
03959 }
03960 else if ( !Q_strncmp( "l_leg", surfName, 5 ) )
03961 {
03962 *hitLoc = HL_LEG_LT;
03963 if ( ent->client != NULL && ent->ghoul2 )
03964 {
03965 mdxaBone_t boltMatrix;
03966 vec3_t tagOrg, angles;
03967
03968 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03969 if (footLBolt>=0)
03970 {
03971 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footLBolt,
03972 &boltMatrix, angles, ent->r.currentOrigin,
03973 actualTime, NULL, ent->modelScale );
03974 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03975 if ( DistanceSquared( point, tagOrg ) < 100 )
03976 {
03977 *hitLoc = HL_FOOT_LT;
03978 }
03979 }
03980 }
03981 }
03982 else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) )
03983 {
03984 *hitLoc = HL_HAND_RT;
03985 }
03986 else if ( !Q_strncmp( "l_hand", surfName, 6 ) )
03987 {
03988 *hitLoc = HL_HAND_LT;
03989 }
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999
04000 if (g_dismember.integer == 100)
04001 {
04002 if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL )
04003 {
04004 dismember = qtrue;
04005 }
04006 else if ( dir && (dir[0] || dir[1] || dir[2]) &&
04007 bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) )
04008 {
04009
04010 if (1)
04011 {
04012 char *tagName = NULL;
04013 float aoa = 0.5f;
04014
04015 switch ( *hitLoc )
04016 {
04017 case HL_LEG_RT:
04018 tagName = "*hips_cap_r_leg";
04019 break;
04020 case HL_LEG_LT:
04021 tagName = "*hips_cap_l_leg";
04022 break;
04023 case HL_WAIST:
04024 tagName = "*hips_cap_torso";
04025 aoa = 0.25f;
04026 break;
04027 case HL_CHEST_RT:
04028 case HL_ARM_RT:
04029 case HL_BACK_LT:
04030 tagName = "*torso_cap_r_arm";
04031 break;
04032 case HL_CHEST_LT:
04033 case HL_ARM_LT:
04034 case HL_BACK_RT:
04035 tagName = "*torso_cap_l_arm";
04036 break;
04037 case HL_HAND_RT:
04038 tagName = "*r_arm_cap_r_hand";
04039 break;
04040 case HL_HAND_LT:
04041 tagName = "*l_arm_cap_l_hand";
04042 break;
04043 case HL_HEAD:
04044 tagName = "*torso_cap_head";
04045 aoa = 0.25f;
04046 break;
04047 case HL_CHEST:
04048 case HL_BACK:
04049 case HL_FOOT_RT:
04050 case HL_FOOT_LT:
04051 default:
04052
04053 break;
04054 }
04055 if ( tagName )
04056 {
04057 int tagBolt = trap_G2API_AddBolt( ent->ghoul2, 0, tagName );
04058 if ( tagBolt != -1 )
04059 {
04060 mdxaBone_t boltMatrix;
04061 vec3_t tagOrg, tagDir, angles;
04062
04063 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
04064 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, tagBolt,
04065 &boltMatrix, angles, ent->r.currentOrigin,
04066 actualTime, NULL, ent->modelScale );
04067 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
04068 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, tagDir );
04069 if ( DistanceSquared( point, tagOrg ) < 256 )
04070 {
04071 float dot = DotProduct( dir, tagDir );
04072 if ( dot < aoa && dot > -aoa )
04073 {
04074 dot = DotProduct( bladeDir, tagDir );
04075 if ( dot < aoa && dot > -aoa )
04076 {
04077 dismember = qtrue;
04078 }
04079 }
04080 }
04081 }
04082 }
04083 }
04084 }
04085 else
04086 {
04087 dismember = qtrue;
04088 }
04089 }
04090 return dismember;
04091 }
04092
04093 void G_CheckForDismemberment(gentity_t *ent, gentity_t *enemy, vec3_t point, int damage, int deathAnim, qboolean postDeath)
04094 {
04095 int hitLoc = -1, hitLocUse = -1;
04096 vec3_t boltPoint;
04097 int dismember = g_dismember.integer;
04098
04099 if (ent->localAnimIndex > 1)
04100 {
04101 if (!ent->NPC)
04102 {
04103 return;
04104 }
04105
04106 if (ent->client->NPC_class != CLASS_PROTOCOL)
04107 {
04108 return;
04109 }
04110 }
04111
04112 if (!dismember)
04113 {
04114 return;
04115 }
04116
04117 if (gGAvoidDismember == 1)
04118 {
04119 return;
04120 }
04121
04122 if (gGAvoidDismember != 2)
04123 {
04124 if (Q_irand(0, 100) > dismember)
04125 {
04126 return;
04127 }
04128
04129 if (damage < 5)
04130 {
04131 return;
04132 }
04133 }
04134
04135 if (gGAvoidDismember == 2)
04136 {
04137 hitLoc = HL_HAND_RT;
04138 }
04139 else
04140 {
04141 if (d_saberGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time)
04142 {
04143 char hitSurface[MAX_QPATH];
04144
04145 trap_G2API_GetSurfaceName(ent->ghoul2, ent->client->g2LastSurfaceHit, 0, hitSurface);
04146
04147 if (hitSurface[0])
04148 {
04149 G_GetHitLocFromSurfName(ent, hitSurface, &hitLoc, point, vec3_origin, vec3_origin, MOD_UNKNOWN);
04150 }
04151 }
04152
04153 if (hitLoc == -1)
04154 {
04155 hitLoc = G_GetHitLocation( ent, point );
04156 }
04157 }
04158
04159 switch(hitLoc)
04160 {
04161 case HL_FOOT_RT:
04162 case HL_LEG_RT:
04163 hitLocUse = G2_MODELPART_RLEG;
04164 break;
04165 case HL_FOOT_LT:
04166 case HL_LEG_LT:
04167 hitLocUse = G2_MODELPART_LLEG;
04168 break;
04169
04170 case HL_WAIST:
04171 hitLocUse = G2_MODELPART_WAIST;
04172 break;
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182 case HL_ARM_RT:
04183 hitLocUse = G2_MODELPART_RARM;
04184 break;
04185 case HL_HAND_RT:
04186 hitLocUse = G2_MODELPART_RHAND;
04187 break;
04188 case HL_ARM_LT:
04189 case HL_HAND_LT:
04190 hitLocUse = G2_MODELPART_LARM;
04191 break;
04192 case HL_HEAD:
04193 hitLocUse = G2_MODELPART_HEAD;
04194 break;
04195 default:
04196 hitLocUse = G_GetHitQuad(ent, point);
04197 break;
04198 }
04199
04200 if (hitLocUse == -1)
04201 {
04202 return;
04203 }
04204
04205 if (ent->client)
04206 {
04207 G_GetDismemberBolt(ent, boltPoint, hitLocUse);
04208 if ( g_austrian.integer
04209 && (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) )
04210 {
04211 G_LogPrintf( "Duel Dismemberment: %s dismembered at %s\n", ent->client->pers.netname, hitLocName[hitLoc] );
04212 }
04213 }
04214 else
04215 {
04216 G_GetDismemberLoc(ent, boltPoint, hitLocUse);
04217 }
04218 G_Dismember(ent, enemy, boltPoint, hitLocUse, 90, 0, deathAnim, postDeath);
04219 }
04220
04221 void G_LocationBasedDamageModifier(gentity_t *ent, vec3_t point, int mod, int dflags, int *damage)
04222 {
04223 int hitLoc = -1;
04224
04225 if (!g_locationBasedDamage.integer)
04226 {
04227 return;
04228 }
04229
04230 if ( (dflags&DAMAGE_NO_HIT_LOC) )
04231 {
04232 return;
04233 }
04234
04235 if (mod == MOD_SABER && *damage <= 1)
04236 {
04237 return;
04238 }
04239
04240 if (!point)
04241 {
04242 return;
04243 }
04244
04245 if ( ent->client && ent->client->NPC_class == CLASS_VEHICLE )
04246 {
04247 return;
04248 }
04249
04250 if ((d_saberGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time && mod == MOD_SABER) ||
04251 (d_projectileGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time))
04252 {
04253 char hitSurface[MAX_QPATH];
04254
04255 trap_G2API_GetSurfaceName(ent->ghoul2, ent->client->g2LastSurfaceHit, 0, hitSurface);
04256
04257 if (hitSurface[0])
04258 {
04259 G_GetHitLocFromSurfName(ent, hitSurface, &hitLoc, point, vec3_origin, vec3_origin, MOD_UNKNOWN);
04260 }
04261 }
04262
04263 if (hitLoc == -1)
04264 {
04265 hitLoc = G_GetHitLocation( ent, point );
04266 }
04267
04268 switch (hitLoc)
04269 {
04270 case HL_FOOT_RT:
04271 case HL_FOOT_LT:
04272 *damage *= 0.5;
04273 break;
04274 case HL_LEG_RT:
04275 case HL_LEG_LT:
04276 *damage *= 0.7;
04277 break;
04278 case HL_WAIST:
04279 case HL_BACK_RT:
04280 case HL_BACK_LT:
04281 case HL_BACK:
04282 case HL_CHEST_RT:
04283 case HL_CHEST_LT:
04284 case HL_CHEST:
04285 break;
04286 case HL_ARM_RT:
04287 case HL_ARM_LT:
04288 *damage *= 0.85;
04289 break;
04290 case HL_HAND_RT:
04291 case HL_HAND_LT:
04292 *damage *= 0.6;
04293 break;
04294 case HL_HEAD:
04295 *damage *= 1.3;
04296 break;
04297 default:
04298 break;
04299 }
04300 }
04301
04302
04303
04304
04305
04306
04307 qboolean G_ThereIsAMaster(void)
04308 {
04309 int i = 0;
04310 gentity_t *ent;
04311
04312 while (i < MAX_CLIENTS)
04313 {
04314 ent = &g_entities[i];
04315
04316 if (ent && ent->client && ent->client->ps.isJediMaster)
04317 {
04318 return qtrue;
04319 }
04320
04321 i++;
04322 }
04323
04324 return qfalse;
04325 }
04326
04327 void G_Knockdown( gentity_t *victim )
04328 {
04329 if ( victim && victim->client && BG_KnockDownable(&victim->client->ps) )
04330 {
04331 victim->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
04332 victim->client->ps.forceDodgeAnim = 0;
04333 victim->client->ps.forceHandExtendTime = level.time + 1100;
04334 victim->client->ps.quickerGetup = qfalse;
04335 }
04336 }
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363 extern qboolean gSiegeRoundBegun;
04364
04365 int gPainMOD = 0;
04366 int gPainHitLoc = -1;
04367 vec3_t gPainPoint;
04368
04369 void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
04370 vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
04371 gclient_t *client;
04372 int take;
04373 int save;
04374 int asave;
04375 int knockback;
04376 int max;
04377 int subamt = 0;
04378 float famt = 0;
04379 float hamt = 0;
04380 float shieldAbsorbed = 0;
04381
04382 if (targ && targ->damageRedirect)
04383 {
04384 G_Damage(&g_entities[targ->damageRedirectTo], inflictor, attacker, dir, point, damage, dflags, mod);
04385 return;
04386 }
04387
04388 if (mod == MOD_DEMP2 && targ && targ->inuse && targ->client)
04389 {
04390 if ( targ->client->ps.electrifyTime < level.time )
04391 {
04392 if (targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE &&
04393 targ->m_pVehicle && (targ->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER || targ->m_pVehicle->m_pVehicleInfo->type == VH_WALKER))
04394 {
04395 targ->client->ps.electrifyTime = level.time + Q_irand( 3000, 4000 );
04396 }
04397 else if ( targ->s.NPC_class != CLASS_VEHICLE
04398 || (targ->m_pVehicle && targ->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER) )
04399 {
04400 targ->client->ps.electrifyTime = level.time + Q_irand( 300, 800 );
04401 }
04402 }
04403 }
04404
04405 if (g_gametype.integer == GT_SIEGE &&
04406 !gSiegeRoundBegun)
04407 {
04408 return;
04409 }
04410
04411 if (!targ->takedamage) {
04412 return;
04413 }
04414
04415 if ( (targ->flags&FL_SHIELDED) && mod != MOD_SABER && !targ->client)
04416 {
04417 return;
04418 }
04419
04420 if ((targ->flags & FL_DMG_BY_SABER_ONLY) && mod != MOD_SABER)
04421 {
04422 return;
04423 }
04424
04425 if ( targ->client )
04426 {
04427
04428 if ( targ->client->ps.clientNum < MAX_CLIENTS && targ->client->ps.m_iVehicleNum )
04429 {
04430 gentity_t *veh = &g_entities[targ->client->ps.m_iVehicleNum];
04431 if ( veh->m_pVehicle && veh->health > 0 )
04432 {
04433 if ( veh->m_pVehicle->m_pVehicleInfo->type == VH_WALKER ||
04434 veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER)
04435 {
04436 if (!(dflags & DAMAGE_NO_PROTECTION))
04437 {
04438 return;
04439 }
04440 }
04441 }
04442 }
04443 }
04444
04445 if ((targ->flags & FL_DMG_BY_HEAVY_WEAP_ONLY))
04446 {
04447 if (mod != MOD_REPEATER_ALT &&
04448 mod != MOD_ROCKET &&
04449 mod != MOD_FLECHETTE_ALT_SPLASH &&
04450 mod != MOD_ROCKET_HOMING &&
04451 mod != MOD_THERMAL &&
04452 mod != MOD_THERMAL_SPLASH &&
04453 mod != MOD_TRIP_MINE_SPLASH &&
04454 mod != MOD_TIMED_MINE_SPLASH &&
04455 mod != MOD_DET_PACK_SPLASH &&
04456 mod != MOD_VEHICLE &&
04457 mod != MOD_CONC &&
04458 mod != MOD_CONC_ALT &&
04459 mod != MOD_SABER &&
04460 mod != MOD_TURBLAST &&
04461 mod != MOD_SUICIDE &&
04462 mod != MOD_FALLING &&
04463 mod != MOD_CRUSH &&
04464 mod != MOD_TELEFRAG &&
04465 mod != MOD_TRIGGER_HURT)
04466 {
04467 if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04468 {
04469 return;
04470 }
04471 }
04472 }
04473
04474 if (targ->flags & FL_BBRUSH)
04475 {
04476 if (mod == MOD_DEMP2 ||
04477 mod == MOD_DEMP2_ALT ||
04478 mod == MOD_BRYAR_PISTOL ||
04479 mod == MOD_BRYAR_PISTOL_ALT ||
04480 mod == MOD_MELEE)
04481 {
04482 if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04483 {
04484 return;
04485 }
04486 }
04487 }
04488
04489 if (targ && targ->client && targ->client->ps.duelInProgress)
04490 {
04491 if (attacker && attacker->client && attacker->s.number != targ->client->ps.duelIndex)
04492 {
04493 return;
04494 }
04495 else if (attacker && attacker->client && mod != MOD_SABER)
04496 {
04497 return;
04498 }
04499 }
04500 if (attacker && attacker->client && attacker->client->ps.duelInProgress)
04501 {
04502 if (targ && targ->client && targ->s.number != attacker->client->ps.duelIndex)
04503 {
04504 return;
04505 }
04506 else if (targ && targ->client && mod != MOD_SABER)
04507 {
04508 return;
04509 }
04510 }
04511
04512 if ( !(dflags & DAMAGE_NO_PROTECTION) )
04513 {
04514 if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)))
04515 {
04516 damage *= 0.5;
04517 }
04518 }
04519
04520
04521
04522 if ( level.intermissionQueued ) {
04523 return;
04524 }
04525 if ( !inflictor ) {
04526 inflictor = &g_entities[ENTITYNUM_WORLD];
04527 }
04528 if ( !attacker ) {
04529 attacker = &g_entities[ENTITYNUM_WORLD];
04530 }
04531
04532
04533
04534
04535 if ( targ->s.eType == ET_MOVER && targ->genericValue4 != 1 ) {
04536 if ( targ->use && targ->moverState == MOVER_POS1 ) {
04537 GlobalUse( targ, inflictor, attacker );
04538 }
04539 return;
04540 }
04541
04542
04543 if ( attacker->client
04544 && attacker != targ
04545 && attacker->s.eType == ET_PLAYER
04546 && g_gametype.integer != GT_SIEGE )
04547 {
04548 max = attacker->client->ps.stats[STAT_MAX_HEALTH];
04549 damage = damage * max / 100;
04550 }
04551
04552 if ( !(dflags&DAMAGE_NO_HIT_LOC) )
04553 {
04554 if (targ->inuse && (targ->client || targ->s.eType == ET_NPC) &&
04555 attacker->inuse && (attacker->client || attacker->s.eType == ET_NPC))
04556 {
04557 G_LocationBasedDamageModifier(targ, point, mod, dflags, &damage);
04558 }
04559 }
04560
04561 if ( targ->client
04562 && targ->client->NPC_class == CLASS_RANCOR
04563 && (!attacker||!attacker->client||attacker->client->NPC_class!=CLASS_RANCOR) )
04564 {
04565
04566 if ( damage < 10 )
04567 {
04568 damage = 0;
04569 }
04570 else if ( damage >= 10 )
04571 {
04572 damage = 10;
04573 }
04574 }
04575
04576 client = targ->client;
04577
04578 if ( client ) {
04579 if ( client->noclip ) {
04580 return;
04581 }
04582 }
04583
04584 if ( !dir ) {
04585 dflags |= DAMAGE_NO_KNOCKBACK;
04586 } else {
04587 VectorNormalize(dir);
04588 }
04589
04590 knockback = damage;
04591 if ( knockback > 200 ) {
04592 knockback = 200;
04593 }
04594 if ( targ->flags & FL_NO_KNOCKBACK ) {
04595 knockback = 0;
04596 }
04597 if ( dflags & DAMAGE_NO_KNOCKBACK ) {
04598 knockback = 0;
04599 }
04600
04601
04602 if ( knockback && targ->client ) {
04603 vec3_t kvel;
04604 float mass;
04605
04606 mass = 200;
04607
04608 if (mod == MOD_SABER)
04609 {
04610 float saberKnockbackScale = g_saberDmgVelocityScale.value;
04611 if ( (dflags&DAMAGE_SABER_KNOCKBACK1)
04612 || (dflags&DAMAGE_SABER_KNOCKBACK2) )
04613 {
04614 if ( !saberKnockbackScale )
04615 {
04616 saberKnockbackScale = 1.0f;
04617 }
04618 if ( attacker
04619 && attacker->client )
04620 {
04621 if ( (dflags&DAMAGE_SABER_KNOCKBACK1) )
04622 {
04623 if ( attacker && attacker->client )
04624 {
04625 saberKnockbackScale *= attacker->client->saber[0].knockbackScale;
04626 }
04627 }
04628 if ( (dflags&DAMAGE_SABER_KNOCKBACK1_B2) )
04629 {
04630 if ( attacker && attacker->client )
04631 {
04632 saberKnockbackScale *= attacker->client->saber[0].knockbackScale2;
04633 }
04634 }
04635 if ( (dflags&DAMAGE_SABER_KNOCKBACK2) )
04636 {
04637 if ( attacker && attacker->client )
04638 {
04639 saberKnockbackScale *= attacker->client->saber[1].knockbackScale;
04640 }
04641 }
04642 if ( (dflags&DAMAGE_SABER_KNOCKBACK2_B2) )
04643 {
04644 if ( attacker && attacker->client )
04645 {
04646 saberKnockbackScale *= attacker->client->saber[1].knockbackScale2;
04647 }
04648 }
04649 }
04650 }
04651 VectorScale (dir, (g_knockback.value * (float)knockback / mass)*saberKnockbackScale, kvel);
04652 }
04653 else
04654 {
04655 VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
04656 }
04657 VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
04658
04659 if (attacker && attacker->client && attacker != targ)
04660 {
04661 float dur = 5000;
04662 float dur2 = 100;
04663 if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE)
04664 {
04665 dur = 25000;
04666 dur2 = 25000;
04667 }
04668 targ->client->ps.otherKiller = attacker->s.number;
04669 targ->client->ps.otherKillerTime = level.time + dur;
04670 targ->client->ps.otherKillerDebounceTime = level.time + dur2;
04671 }
04672
04673
04674 if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER || (dflags&DAMAGE_SABER_KNOCKBACK1) || (dflags&DAMAGE_SABER_KNOCKBACK2) || (dflags&DAMAGE_SABER_KNOCKBACK1_B2) || (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) ) {
04675 int t;
04676
04677 t = knockback * 2;
04678 if ( t < 50 ) {
04679 t = 50;
04680 }
04681 if ( t > 200 ) {
04682 t = 200;
04683 }
04684 targ->client->ps.pm_time = t;
04685 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
04686 }
04687 }
04688 else if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE && attacker != targ)
04689 {
04690 targ->client->ps.otherKiller = attacker->s.number;
04691 targ->client->ps.otherKillerTime = level.time + 25000;
04692 targ->client->ps.otherKillerDebounceTime = level.time + 25000;
04693 }
04694
04695
04696 if ( (g_trueJedi.integer || g_gametype.integer == GT_SIEGE)
04697 && client )
04698 {
04699 if ( client->ps.trueJedi
04700 || (g_gametype.integer == GT_SIEGE&&client->ps.weapon == WP_SABER))
04701 {
04702 switch ( mod )
04703 {
04704 case MOD_REPEATER_ALT:
04705 case MOD_REPEATER_ALT_SPLASH:
04706 case MOD_DEMP2_ALT:
04707 case MOD_FLECHETTE_ALT_SPLASH:
04708 case MOD_ROCKET:
04709 case MOD_ROCKET_SPLASH:
04710 case MOD_ROCKET_HOMING:
04711 case MOD_ROCKET_HOMING_SPLASH:
04712 case MOD_THERMAL:
04713 case MOD_THERMAL_SPLASH:
04714 case MOD_TRIP_MINE_SPLASH:
04715 case MOD_TIMED_MINE_SPLASH:
04716 case MOD_DET_PACK_SPLASH:
04717 damage *= 0.75;
04718 break;
04719 }
04720 }
04721 else if ( (client->ps.trueNonJedi || (g_gametype.integer == GT_SIEGE&&client->ps.weapon != WP_SABER))
04722 && mod == MOD_SABER )
04723 {
04724 if ( damage < 100 )
04725 {
04726 damage *= 4;
04727 if ( damage > 100 )
04728 {
04729 damage = 100;
04730 }
04731 }
04732 }
04733 }
04734
04735 if (attacker->client && targ->client && g_gametype.integer == GT_SIEGE &&
04736 targ->client->siegeClass != -1 && (bgSiegeClasses[targ->client->siegeClass].classflags & (1<<CFL_STRONGAGAINSTPHYSICAL)))
04737 {
04738
04739 damage *= 0.5;
04740 }
04741
04742
04743 if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
04744
04745
04746
04747 if ( targ != attacker)
04748 {
04749 if (OnSameTeam (targ, attacker))
04750 {
04751 if ( !g_friendlyFire.integer )
04752 {
04753 return;
04754 }
04755 }
04756 else if (attacker && attacker->inuse &&
04757 !attacker->client && attacker->activator &&
04758 targ != attacker->activator &&
04759 attacker->activator->inuse && attacker->activator->client)
04760 {
04761 if (OnSameTeam (targ, attacker->activator))
04762 {
04763 if ( !g_friendlyFire.integer )
04764 {
04765 return;
04766 }
04767 }
04768 }
04769 else if (targ->inuse && targ->client &&
04770 g_gametype.integer >= GT_TEAM &&
04771 attacker->s.number >= MAX_CLIENTS &&
04772 attacker->alliedTeam &&
04773 targ->client->sess.sessionTeam == attacker->alliedTeam &&
04774 !g_friendlyFire.integer)
04775 {
04776 return;
04777 }
04778 }
04779
04780 if (g_gametype.integer == GT_JEDIMASTER && !g_friendlyFire.integer &&
04781 targ && targ->client && attacker && attacker->client &&
04782 targ != attacker && !targ->client->ps.isJediMaster && !attacker->client->ps.isJediMaster &&
04783 G_ThereIsAMaster())
04784 {
04785 return;
04786 }
04787
04788 if (targ->s.number >= MAX_CLIENTS && targ->client
04789 && targ->s.shouldtarget && targ->s.teamowner &&
04790 attacker && attacker->inuse && attacker->client && targ->s.owner >= 0 && targ->s.owner < MAX_CLIENTS)
04791 {
04792 gentity_t *targown = &g_entities[targ->s.owner];
04793
04794 if (targown && targown->inuse && targown->client && OnSameTeam(targown, attacker))
04795 {
04796 if (!g_friendlyFire.integer)
04797 {
04798 return;
04799 }
04800 }
04801 }
04802
04803
04804 if ( (targ->flags & FL_GODMODE) && targ->s.eType != ET_NPC ) {
04805 return;
04806 }
04807
04808 if (targ && targ->client && (targ->client->ps.eFlags & EF_INVULNERABLE) &&
04809 attacker && attacker->client && targ != attacker)
04810 {
04811 if (targ->client->invulnerableTimer <= level.time)
04812 {
04813 targ->client->ps.eFlags &= ~EF_INVULNERABLE;
04814 }
04815 else
04816 {
04817 return;
04818 }
04819 }
04820 }
04821
04822
04823
04824 if ( attacker && !targ->client )
04825 {
04826 if ( g_gametype.integer == GT_SIEGE &&
04827 !g_ff_objectives.integer )
04828 {
04829 if ( targ->teamnodmg )
04830 {
04831 if ( attacker->client )
04832 {
04833 if ( targ->teamnodmg == attacker->client->sess.sessionTeam )
04834 {
04835 return;
04836 }
04837 }
04838 else if ( attacker->teamnodmg )
04839 {
04840
04841 if ( targ->teamnodmg == attacker->teamnodmg )
04842 {
04843 if (attacker->activator &&
04844 attacker->activator->inuse &&
04845 attacker->activator->s.number < MAX_CLIENTS &&
04846 attacker->activator->client &&
04847 attacker->activator->client->sess.sessionTeam != targ->teamnodmg)
04848 {
04849 }
04850 else
04851 {
04852 return;
04853 }
04854 }
04855 }
04856 }
04857 }
04858 }
04859
04860
04861
04862 if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
04863 G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
04864 if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
04865 return;
04866 }
04867 damage *= 0.5;
04868 }
04869
04870
04871 if ( attacker->client && targ != attacker && targ->health > 0
04872 && targ->s.eType != ET_MISSILE
04873 && targ->s.eType != ET_GENERAL
04874 && client) {
04875 if ( OnSameTeam( targ, attacker ) ) {
04876 attacker->client->ps.persistant[PERS_HITS]--;
04877 } else {
04878 attacker->client->ps.persistant[PERS_HITS]++;
04879 }
04880 attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
04881 }
04882
04883
04884
04885 if ( targ == attacker && !(dflags & DAMAGE_NO_SELF_PROTECTION)) {
04886 if ( g_gametype.integer == GT_SIEGE )
04887 {
0