codemp/game/g_combat.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // g_combat.c
00004 
00005 //#include "g_local.h"
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 //rww - pd
00016 void BotDamageNotification(gclient_t *bot, gentity_t *attacker);
00017 //end rww
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         //remove my script_targetname
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         // Get target forward, right and up.
00056         if(target->client)
00057         {
00058                 // Ignore player's pitch and roll.
00059                 VectorSet(tangles, 0, target->r.currentAngles[YAW], 0);
00060         }
00061 
00062         AngleVectors(tangles, forward, right, up);
00063 
00064         // Get center of target.
00065         VectorAdd(target->r.absmin, target->r.absmax, tcenter);
00066         VectorScale(tcenter, 0.5, tcenter);
00067 
00068         // Get radius width of target.
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         // Get impact point.
00072         if(ppoint && !VectorCompare(ppoint, vec3_origin))
00073         {
00074                 VectorCopy(ppoint, point);
00075         }
00076         else
00077         {
00078                 return HL_NONE;
00079         }
00080 
00081 /*
00082 //get impact dir
00083         if(pdir && !VectorCompare(pdir, vec3_origin))
00084         {
00085                 VectorCopy(pdir, dir);
00086         }
00087         else
00088         {
00089                 return;
00090         }
00091 
00092 //put point at controlled distance from center
00093         VectorSubtract(point, tcenter, tempvec);
00094         tempvec[2] = 0;
00095         hdist = VectorLength(tempvec);
00096 
00097         VectorMA(point, hdist - tradius, dir, point);
00098         //now a point on the surface of a cylinder with a radius of tradius
00099 */      
00100         VectorSubtract(point, tcenter, point_dir);
00101         VectorNormalize(point_dir);
00102 
00103         // Get bottom to top (vertical) position index
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         // Get back to front (forward) position index.
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         // Get left to right (lateral) position index.
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                 // Feet.
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                 // Legs.
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                 // Hands.
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                 // Arms.
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                 // Head.
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 int G_PickPainAnim( gentity_t *self, vec3_t point, int damage )
00269 {
00270         switch( G_GetHitLocation( self, point ) )
00271         {
00272         case HL_FOOT_RT:
00273                 return BOTH_PAIN12;
00274                 //PAIN12 = right foot
00275                 break;
00276         case HL_FOOT_LT:
00277                 return -1;
00278                 break;
00279         case HL_LEG_RT:
00280                 if ( !Q_irand( 0, 1 ) )
00281                 {
00282                         return BOTH_PAIN11;
00283                 }
00284                 else
00285                 {
00286                         return BOTH_PAIN13;
00287                 }
00288                 //PAIN11 = twitch right leg
00289                 //PAIN13 = right knee
00290                 break;
00291         case HL_LEG_LT:
00292                 return BOTH_PAIN14;
00293                 //PAIN14 = twitch left leg
00294                 break;
00295         case HL_BACK_RT:
00296                 return BOTH_PAIN7;
00297                 //PAIN7 = med left shoulder
00298                 break;
00299         case HL_BACK_LT:
00300                 return Q_irand( BOTH_PAIN15, BOTH_PAIN16 );
00301                 //PAIN15 = med right shoulder
00302                 //PAIN16 = twitch right shoulder
00303                 break;
00304         case HL_BACK:
00305                 if ( !Q_irand( 0, 1 ) )
00306                 {
00307                         return BOTH_PAIN1;
00308                 }
00309                 else
00310                 {
00311                         return BOTH_PAIN5;
00312                 }
00313                 //PAIN1 = back
00314                 //PAIN5 = same as 1
00315                 break;
00316         case HL_CHEST_RT:
00317                 return BOTH_PAIN3;
00318                 //PAIN3 = long, right shoulder
00319                 break;
00320         case HL_CHEST_LT:
00321                 return BOTH_PAIN2;
00322                 //PAIN2 = long, left shoulder
00323                 break;
00324         case HL_WAIST:
00325         case HL_CHEST:
00326                 if ( !Q_irand( 0, 3 ) )
00327                 {
00328                         return BOTH_PAIN6;
00329                 }
00330                 else if ( !Q_irand( 0, 2 ) )
00331                 {
00332                         return BOTH_PAIN8;
00333                 }
00334                 else if ( !Q_irand( 0, 1 ) )
00335                 {
00336                         return BOTH_PAIN17;
00337                 }
00338                 else
00339                 {
00340                         return BOTH_PAIN19;
00341                 }
00342                 //PAIN6 = gut
00343                 //PAIN8 = chest
00344                 //PAIN17 = twitch crotch
00345                 //PAIN19 = med crotch
00346                 break;
00347         case HL_ARM_RT:
00348         case HL_HAND_RT:
00349                 return BOTH_PAIN9;
00350                 //PAIN9 = twitch right arm
00351                 break;
00352         case HL_ARM_LT:
00353         case HL_HAND_LT:
00354                 return BOTH_PAIN10;
00355                 //PAIN10 = twitch left arm
00356                 break;
00357         case HL_HEAD:
00358                 return BOTH_PAIN4;
00359                 //PAIN4 = head
00360                 break;
00361         default:
00362                 return -1;
00363                 break;
00364         }
00365 }
00366 */
00367 
00368 void ExplodeDeath( gentity_t *self ) 
00369 {
00370 //      gentity_t       *tent;
00371         vec3_t          forward;
00372 
00373         self->takedamage = qfalse;//stop chain reaction runaway loops
00374 
00375         self->s.loopSound = 0;
00376         self->s.loopIsSoundset = qfalse;
00377 
00378         VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
00379 
00380 //      tent = G_TempEntity( self->s.origin, EV_FX_EXPLOSION );
00381         AngleVectors(self->s.angles, forward, NULL, NULL);
00382 
00383 /*      
00384         if ( self->fxID > 0 )
00385         {
00386                 G_PlayEffect( self->fxID, self->r.currentOrigin, forward );
00387         }
00388         else
00389         */
00390 
00391         {
00392 //              CG_SurfaceExplosion( self->r.currentOrigin, forward, 20.0f, 12.0f, ((self->spawnflags&4)==qfalse) );    //FIXME: This needs to be consistent to all exploders!
00393 //              G_Sound(self, self->sounds );
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 ScorePlum
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         // only send this temp entity to a single client
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 AddScore
00431 
00432 Adds score to both the client and his team
00433 ============
00434 */
00435 extern qboolean g_dontPenalizeTeam; //g_cmds.c
00436 void AddScore( gentity_t *ent, vec3_t origin, int score )
00437 {
00438         /*
00439         if (g_gametype.integer == GT_SIEGE)
00440         { //no scoring in this gametype at all.
00441                 return;
00442         }
00443         */
00444 
00445         if ( !ent->client ) {
00446                 return;
00447         }
00448         // no scoring during pre-match warmup
00449         if ( level.warmupTime ) {
00450                 return;
00451         }
00452         // show score plum
00453         //ScorePlum(ent, origin, score);
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 TossClientItems
00464 
00465 rww - Toss the weapon away from the player in the specified direction
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         { //no dropping weaps
00478                 return;
00479         }
00480 
00481         if (weapon <= WP_BRYAR_PISTOL)
00482         { //can't have this
00483                 return;
00484         }
00485 
00486         if (weapon == WP_EMPLACED_GUN ||
00487                 weapon == WP_TURRET)
00488         {
00489                 return;
00490         }
00491 
00492         // find the item type for this weapon
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                 { //no ammo
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                         { //this one's good
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 TossClientItems
00563 
00564 Toss the weapon and powerups for the killed player
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         { //just don't drop anything then
00576                 return;
00577         }
00578 
00579         // drop the weapon if not a gauntlet or machinegun
00580         weapon = self->s.weapon;
00581 
00582         // make a special check to see if they are changing to a new
00583         // weapon that isn't the mg or gauntlet.  Without this, a client
00584         // can pick up a weapon, be killed, and not drop the weapon because
00585         // their weapon change hasn't completed yet and they are still holding the MG.
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                 // find the item type for this weapon
00604                 item = BG_FindItemForWeapon( weapon );
00605 
00606                 // tell all clients to remove the weapon model on this guy until he respawns
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                 // spawn the item
00612                 Drop_Item( self, item, 0 );
00613         }
00614 
00615         // drop all the powerups if not in teamplay
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                                 // decide how many seconds it has left
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 LookAtKiller
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 GibEntity
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 body_die
00683 ==================
00684 */
00685 void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
00686         // NOTENOTE No gibbing right now, this is star wars.
00687         qboolean doDisint = qfalse;
00688 
00689         if (self->s.eType == ET_NPC)
00690         { //well, just rem it then, so long as it's done with its death anim and it's not a standard weapon.
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                         //since it's the corpse entity, tell it to "remove" itself
00745                         self->think = BodyRid;
00746                         self->nextthink = level.time + 1000;
00747                 }
00748                 return;
00749         }
00750 }
00751 
00752 
00753 // these are just for logging, the client prints its own messages
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 CheckAlmostCapture
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         // if this player was carrying a flag
00812         if ( self->client->ps.powerups[PW_REDFLAG] ||
00813                 self->client->ps.powerups[PW_BLUEFLAG] ||
00814                 self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00815                 // get the goal flag this player should have been going for
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                 // if we found the destination flag and it's not picked up
00838                 if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
00839                         // if the player was *very* close
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;            //# Death anim from a roll
00888         }
00889         else if ( BG_FlippingAnim( self->client->ps.legsAnim ) )
00890         {
00891                 deathAnim = BOTH_DEATH_FLIP;            //# Death anim from a flip
00892         }
00893         else if ( G_InKnockDown( &self->client->ps ) )
00894         {//since these happen a lot, let's handle them case by case
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                         {//on our way down
00901                                 if ( self->client->ps.legsTimer > 600 )
00902                                 {//still partially up
00903                                         deathAnim = BOTH_DEATH_FALLING_UP;
00904                                 }
00905                                 else
00906                                 {//down
00907                                         deathAnim = BOTH_DEATH_LYING_UP;
00908                                 }
00909                         }
00910                         break;
00911                 case BOTH_KNOCKDOWN2:
00912                         if ( animLength - self->client->ps.legsTimer > 700 )
00913                         {//on our way down
00914                                 if ( self->client->ps.legsTimer > 600 )
00915                                 {//still partially up
00916                                         deathAnim = BOTH_DEATH_FALLING_UP;
00917                                 }
00918                                 else
00919                                 {//down
00920                                         deathAnim = BOTH_DEATH_LYING_UP;
00921                                 }
00922                         }
00923                         break;
00924                 case BOTH_KNOCKDOWN3:
00925                         if ( animLength - self->client->ps.legsTimer > 100 )
00926                         {//on our way down
00927                                 if ( self->client->ps.legsTimer > 1300 )
00928                                 {//still partially up
00929                                         deathAnim = BOTH_DEATH_FALLING_DN;
00930                                 }
00931                                 else
00932                                 {//down
00933                                         deathAnim = BOTH_DEATH_LYING_DN;
00934                                 }
00935                         }
00936                         break;
00937                 case BOTH_KNOCKDOWN4:
00938                         if ( animLength - self->client->ps.legsTimer > 300 )
00939                         {//on our way down
00940                                 if ( self->client->ps.legsTimer > 350 )
00941                                 {//still partially up
00942                                         deathAnim = BOTH_DEATH_FALLING_UP;
00943                                 }
00944                                 else
00945                                 {//down
00946                                         deathAnim = BOTH_DEATH_LYING_UP;
00947                                 }
00948                         }
00949                         else
00950                         {//crouch death
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;        //# Death anim when crouched and thrown back
00960                                 }
00961                                 else
00962                                 {
00963                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
00964                                 }
00965                         }
00966                         break;
00967                 case BOTH_KNOCKDOWN5:
00968                         if ( self->client->ps.legsTimer < 750 )
00969                         {//flat
00970                                 deathAnim = BOTH_DEATH_LYING_DN;
00971                         }
00972                         break;
00973                 case BOTH_GETUP1:
00974                         if ( self->client->ps.legsTimer < 350 )
00975                         {//standing up
00976                         }
00977                         else if ( self->client->ps.legsTimer < 800 )
00978                         {//crouching
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;        //# Death anim when crouched and thrown back
00987                                 }
00988                                 else
00989                                 {
00990                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
00991                                 }
00992                         }
00993                         else
00994                         {//lying down
00995                                 if ( animLength - self->client->ps.legsTimer > 450 )
00996                                 {//partially up
00997                                         deathAnim = BOTH_DEATH_FALLING_UP;
00998                                 }
00999                                 else
01000                                 {//down
01001                                         deathAnim = BOTH_DEATH_LYING_UP;
01002                                 }
01003                         }
01004                         break;
01005                 case BOTH_GETUP2:
01006                         if ( self->client->ps.legsTimer < 150 )
01007                         {//standing up
01008                         }
01009                         else if ( self->client->ps.legsTimer < 850 )
01010                         {//crouching
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;        //# Death anim when crouched and thrown back
01020                                 }
01021                                 else
01022                                 {
01023                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01024                                 }
01025                         }
01026                         else
01027                         {//lying down
01028                                 if ( animLength - self->client->ps.legsTimer > 500 )
01029                                 {//partially up
01030                                         deathAnim = BOTH_DEATH_FALLING_UP;
01031                                 }
01032                                 else
01033                                 {//down
01034                                         deathAnim = BOTH_DEATH_LYING_UP;
01035                                 }
01036                         }
01037                         break;
01038                 case BOTH_GETUP3:
01039                         if ( self->client->ps.legsTimer < 250 )
01040                         {//standing up
01041                         }
01042                         else if ( self->client->ps.legsTimer < 600 )
01043                         {//crouching
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;        //# Death anim when crouched and thrown back
01052                                 }
01053                                 else
01054                                 {
01055                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01056                                 }
01057                         }
01058                         else
01059                         {//lying down
01060                                 if ( animLength - self->client->ps.legsTimer > 150 )
01061                                 {//partially up
01062                                         deathAnim = BOTH_DEATH_FALLING_DN;
01063                                 }
01064                                 else
01065                                 {//down
01066                                         deathAnim = BOTH_DEATH_LYING_DN;
01067                                 }
01068                         }
01069                         break;
01070                 case BOTH_GETUP4:
01071                         if ( self->client->ps.legsTimer < 250 )
01072                         {//standing up
01073                         }
01074                         else if ( self->client->ps.legsTimer < 600 )
01075                         {//crouching
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;        //# Death anim when crouched and thrown back
01085                                 }
01086                                 else
01087                                 {
01088                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01089                                 }
01090                         }
01091                         else
01092                         {//lying down
01093                                 if ( animLength - self->client->ps.legsTimer > 850 )
01094                                 {//partially up
01095                                         deathAnim = BOTH_DEATH_FALLING_DN;
01096                                 }
01097                                 else
01098                                 {//down
01099                                         deathAnim = BOTH_DEATH_LYING_UP;
01100                                 }
01101                         }
01102                         break;
01103                 case BOTH_GETUP5:
01104                         if ( self->client->ps.legsTimer > 850 )
01105                         {//lying down
01106                                 if ( animLength - self->client->ps.legsTimer > 1500 )
01107                                 {//partially up
01108                                         deathAnim = BOTH_DEATH_FALLING_DN;
01109                                 }
01110                                 else
01111                                 {//down
01112                                         deathAnim = BOTH_DEATH_LYING_DN;
01113                                 }
01114                         }
01115                         break;
01116                 case BOTH_GETUP_CROUCH_B1:
01117                         if ( self->client->ps.legsTimer < 800 )
01118                         {//crouching
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;        //# Death anim when crouched and thrown back
01128                                 }
01129                                 else
01130                                 {
01131                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01132                                 }
01133                         }
01134                         else
01135                         {//lying down
01136                                 if ( animLength - self->client->ps.legsTimer > 400 )
01137                                 {//partially up
01138                                         deathAnim = BOTH_DEATH_FALLING_UP;
01139                                 }
01140                                 else
01141                                 {//down
01142                                         deathAnim = BOTH_DEATH_LYING_UP;
01143                                 }
01144                         }
01145                         break;
01146                 case BOTH_GETUP_CROUCH_F1:
01147                         if ( self->client->ps.legsTimer < 800 )
01148                         {//crouching
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;        //# Death anim when crouched and thrown back
01158                                 }
01159                                 else
01160                                 {
01161                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01162                                 }
01163                         }
01164                         else
01165                         {//lying down
01166                                 if ( animLength - self->client->ps.legsTimer > 150 )
01167                                 {//partially up
01168                                         deathAnim = BOTH_DEATH_FALLING_DN;
01169                                 }
01170                                 else
01171                                 {//down
01172                                         deathAnim = BOTH_DEATH_LYING_DN;
01173                                 }
01174                         }
01175                         break;
01176                 case BOTH_FORCE_GETUP_B1:
01177                         if ( self->client->ps.legsTimer < 325 )
01178                         {//standing up
01179                         }
01180                         else if ( self->client->ps.legsTimer < 725 )
01181                         {//spinning up
01182                                 deathAnim = BOTH_DEATH_SPIN_180;        //# Death anim when facing backwards
01183                         }
01184                         else if ( self->client->ps.legsTimer < 900 )
01185                         {//crouching
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;        //# Death anim when crouched and thrown back
01195                                 }
01196                                 else
01197                                 {
01198                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01199                                 }
01200                         }
01201                         else
01202                         {//lying down
01203                                 if ( animLength - self->client->ps.legsTimer > 50 )
01204                                 {//partially up
01205                                         deathAnim = BOTH_DEATH_FALLING_UP;
01206                                 }
01207                                 else
01208                                 {//down
01209                                         deathAnim = BOTH_DEATH_LYING_UP;
01210                                 }
01211                         }
01212                         break;
01213                 case BOTH_FORCE_GETUP_B2:
01214                         if ( self->client->ps.legsTimer < 575 )
01215                         {//standing up
01216                         }
01217                         else if ( self->client->ps.legsTimer < 875 )
01218                         {//spinning up
01219                                 deathAnim = BOTH_DEATH_SPIN_180;        //# Death anim when facing backwards
01220                         }
01221                         else if ( self->client->ps.legsTimer < 900 )
01222                         {//crouching
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;        //# Death anim when crouched and thrown back
01232                                 }
01233                                 else
01234                                 {
01235                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01236                                 }
01237                         }
01238                         else
01239                         {//lying down
01240                                 //partially up
01241                                 deathAnim = BOTH_DEATH_FALLING_UP;
01242                         }
01243                         break;
01244                 case BOTH_FORCE_GETUP_B3:
01245                         if ( self->client->ps.legsTimer < 150 )
01246                         {//standing up
01247                         }
01248                         else if ( self->client->ps.legsTimer < 775 )
01249                         {//flipping
01250                                 deathAnim = BOTH_DEATHBACKWARD2; //backflip
01251                         }
01252                         else
01253                         {//lying down
01254                                 //partially up
01255                                 deathAnim = BOTH_DEATH_FALLING_UP;
01256                         }
01257                         break;
01258                 case BOTH_FORCE_GETUP_B4:
01259                         if ( self->client->ps.legsTimer < 325 )
01260                         {//standing up
01261                         }
01262                         else
01263                         {//lying down
01264                                 if ( animLength - self->client->ps.legsTimer > 150 )
01265                                 {//partially up
01266                                         deathAnim = BOTH_DEATH_FALLING_UP;
01267                                 }
01268                                 else
01269                                 {//down
01270                                         deathAnim = BOTH_DEATH_LYING_UP;
01271                                 }
01272                         }
01273                         break;
01274                 case BOTH_FORCE_GETUP_B5:
01275                         if ( self->client->ps.legsTimer < 550 )
01276                         {//standing up
01277                         }
01278                         else if ( self->client->ps.legsTimer < 1025 )
01279                         {//kicking up
01280                                 deathAnim = BOTH_DEATHBACKWARD2; //backflip
01281                         }
01282                         else
01283                         {//lying down
01284                                 if ( animLength - self->client->ps.legsTimer > 50 )
01285                                 {//partially up
01286                                         deathAnim = BOTH_DEATH_FALLING_UP;
01287                                 }
01288                                 else
01289                                 {//down
01290                                         deathAnim = BOTH_DEATH_LYING_UP;
01291                                 }
01292                         }
01293                         break;
01294                 case BOTH_FORCE_GETUP_B6:
01295                         if ( self->client->ps.legsTimer < 225 )
01296                         {//standing up
01297                         }
01298                         else if ( self->client->ps.legsTimer < 425 )
01299                         {//crouching up
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;        //# Death anim when crouched and thrown back
01309                                 }
01310                                 else
01311                                 {
01312                                         deathAnim = BOTH_DEATH_CROUCHED;        //# Death anim when crouched
01313                                 }
01314                         }
01315                         else if ( self->client->ps.legsTimer < 825 )
01316                         {//flipping up
01317                                 deathAnim = BOTH_DEATHFORWARD3; //backflip
01318                         }
01319                         else
01320                         {//lying down
01321                                 if ( animLength - self->client->ps.legsTimer > 225 )
01322                                 {//partially up
01323                                         deathAnim = BOTH_DEATH_FALLING_UP;
01324                                 }
01325                                 else
01326                                 {//down
01327                                         deathAnim = BOTH_DEATH_LYING_UP;
01328                                 }
01329                         }
01330                         break;
01331                 case BOTH_FORCE_GETUP_F1:
01332                         if ( self->client->ps.legsTimer < 275 )
01333                         {//standing up
01334                         }
01335                         else if ( self->client->ps.legsTimer < 750 )
01336                         {//flipping
01337                                 deathAnim = BOTH_DEATH14;
01338                         }
01339                         else
01340                         {//lying down
01341