Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

g_combat.c File Reference

#include "g_local.h"

Include dependency graph for g_combat.c:

Include dependency graph

Go to the source code of this file.

Functions

void AddScore (gentity_t *ent, vec3_t origin, int score)
void body_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
qboolean CanDamage (gentity_t *targ, vec3_t origin)
void CheckAlmostCapture (gentity_t *self, gentity_t *attacker)
void CheckAlmostScored (gentity_t *self, gentity_t *attacker)
int CheckArmor (gentity_t *ent, int damage, int dflags)
void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod)
qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod)
void GibEntity (gentity_t *self, int killer)
void LookAtKiller (gentity_t *self, gentity_t *inflictor, gentity_t *attacker)
void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
int RaySphereIntersections (vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2])
void ScorePlum (gentity_t *ent, vec3_t origin, int score)
void TossClientItems (gentity_t *self)

Variables

char * modNames []


Function Documentation

void AddScore gentity_t ent,
vec3_t  origin,
int  score
 

Definition at line 52 of file g_combat.c.

References CalculateRanks(), gentity_s::client, g_gametype, gentity_t, level, playerState_s::persistant, gclient_s::ps, ScorePlum(), level_locals_t::teamScores, and level_locals_t::warmupTime.

Referenced by player_die(), Team_FragBonuses(), Team_TouchEnemyFlag(), Team_TouchOurFlag(), and Use_Target_Score().

00052                                                           {
00053     if ( !ent->client ) {
00054         return;
00055     }
00056     // no scoring during pre-match warmup
00057     if ( level.warmupTime ) {
00058         return;
00059     }
00060     // show score plum
00061     ScorePlum(ent, origin, score);
00062     //
00063     ent->client->ps.persistant[PERS_SCORE] += score;
00064     if ( g_gametype.integer == GT_TEAM )
00065         level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
00066     CalculateRanks();
00067 }

Here is the call graph for this function:

void body_die gentity_t self,
gentity_t inflictor,
gentity_t attacker,
int  damage,
int  meansOfDeath
 

Definition at line 272 of file g_combat.c.

References g_blood, gentity_t, GIB_HEALTH, GibEntity(), and vmCvar_t::integer.

00272                                                                                                           {
00273     if ( self->health > GIB_HEALTH ) {
00274         return;
00275     }
00276     if ( !g_blood.integer ) {
00277         self->health = GIB_HEALTH+1;
00278         return;
00279     }
00280 
00281     GibEntity( self, 0 );
00282 }

Here is the call graph for this function:

qboolean CanDamage gentity_t targ,
vec3_t  origin
 

Definition at line 1078 of file g_combat.c.

References entityShared_t::absmax, entityShared_t::absmin, ENTITYNUM_NONE, gentity_t, MASK_SOLID, entityState_s::number, qboolean, gentity_s::r, gentity_s::s, tr, trap_Trace(), vec3_origin, vec3_t, VectorAdd, VectorCopy, and VectorScale.

Referenced by G_RadiusDamage().

01078                                                     {
01079     vec3_t  dest;
01080     trace_t tr;
01081     vec3_t  midpoint;
01082 
01083     // use the midpoint of the bounds instead of the origin, because
01084     // bmodels may have their origin is 0,0,0
01085     VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
01086     VectorScale (midpoint, 0.5, midpoint);
01087 
01088     VectorCopy (midpoint, dest);
01089     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01090     if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
01091         return qtrue;
01092 
01093     // this should probably check in the plane of projection, 
01094     // rather than in world coordinate, and also include Z
01095     VectorCopy (midpoint, dest);
01096     dest[0] += 15.0;
01097     dest[1] += 15.0;
01098     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01099     if (tr.fraction == 1.0)
01100         return qtrue;
01101 
01102     VectorCopy (midpoint, dest);
01103     dest[0] += 15.0;
01104     dest[1] -= 15.0;
01105     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01106     if (tr.fraction == 1.0)
01107         return qtrue;
01108 
01109     VectorCopy (midpoint, dest);
01110     dest[0] -= 15.0;
01111     dest[1] += 15.0;
01112     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01113     if (tr.fraction == 1.0)
01114         return qtrue;
01115 
01116     VectorCopy (midpoint, dest);
01117     dest[0] -= 15.0;
01118     dest[1] -= 15.0;
01119     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
01120     if (tr.fraction == 1.0)
01121         return qtrue;
01122 
01123 
01124     return qfalse;
01125 }

Here is the call graph for this function:

void CheckAlmostCapture gentity_t self,
gentity_t attacker
 

Definition at line 356 of file g_combat.c.

References gentity_s::client, gentity_s::flags, FOFS, G_Find(), g_gametype, gentity_t, entityState_s::origin, playerState_s::origin, playerState_s::persistant, gclient_s::ps, gentity_s::r, gentity_s::s, entityShared_t::svFlags, vec3_t, VectorLength(), and VectorSubtract.

Referenced by player_die().

00356                                                                 {
00357     gentity_t   *ent;
00358     vec3_t      dir;
00359     char        *classname;
00360 
00361     // if this player was carrying a flag
00362     if ( self->client->ps.powerups[PW_REDFLAG] ||
00363         self->client->ps.powerups[PW_BLUEFLAG] ||
00364         self->client->ps.powerups[PW_NEUTRALFLAG] ) {
00365         // get the goal flag this player should have been going for
00366         if ( g_gametype.integer == GT_CTF ) {
00367             if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00368                 classname = "team_CTF_blueflag";
00369             }
00370             else {
00371                 classname = "team_CTF_redflag";
00372             }
00373         }
00374         else {
00375             if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00376                 classname = "team_CTF_redflag";
00377             }
00378             else {
00379                 classname = "team_CTF_blueflag";
00380             }
00381         }
00382         ent = NULL;
00383         do
00384         {
00385             ent = G_Find(ent, FOFS(classname), classname);
00386         } while (ent && (ent->flags & FL_DROPPED_ITEM));
00387         // if we found the destination flag and it's not picked up
00388         if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
00389             // if the player was *very* close
00390             VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00391             if ( VectorLength(dir) < 200 ) {
00392                 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00393                 if ( attacker->client ) {
00394                     attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00395                 }
00396             }
00397         }
00398     }
00399 }

Here is the call graph for this function:

void CheckAlmostScored gentity_t self,
gentity_t attacker
 

Definition at line 406 of file g_combat.c.

References gentity_s::client, FOFS, G_Find(), gentity_t, NULL, entityState_s::origin, playerState_s::origin, playerState_s::persistant, gclient_s::ps, gentity_s::s, vec3_t, VectorLength(), and VectorSubtract.

Referenced by player_die().

00406                                                                {
00407     gentity_t   *ent;
00408     vec3_t      dir;
00409     char        *classname;
00410 
00411     // if the player was carrying cubes
00412     if ( self->client->ps.generic1 ) {
00413         if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
00414             classname = "team_redobelisk";
00415         }
00416         else {
00417             classname = "team_blueobelisk";
00418         }
00419         ent = G_Find(NULL, FOFS(classname), classname);
00420         // if we found the destination obelisk
00421         if ( ent ) {
00422             // if the player was *very* close
00423             VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
00424             if ( VectorLength(dir) < 200 ) {
00425                 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00426                 if ( attacker->client ) {
00427                     attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
00428                 }
00429             }
00430         }
00431     }
00432 }

Here is the call graph for this function:

int CheckArmor gentity_t ent,
int  damage,
int  dflags
 

Definition at line 690 of file g_combat.c.

References ARMOR_PROTECTION, ceil(), gentity_s::client, count, gclient_t, gentity_t, gclient_s::ps, and playerState_s::stats.

Referenced by G_Damage().

00691 {
00692     gclient_t   *client;
00693     int         save;
00694     int         count;
00695 
00696     if (!damage)
00697         return 0;
00698 
00699     client = ent->client;
00700 
00701     if (!client)
00702         return 0;
00703 
00704     if (dflags & DAMAGE_NO_ARMOR)
00705         return 0;
00706 
00707     // armor
00708     count = client->ps.stats[STAT_ARMOR];
00709     save = ceil( damage * ARMOR_PROTECTION );
00710     if (save >= count)
00711         save = count;
00712 
00713     if (!save)
00714         return 0;
00715 
00716     client->ps.stats[STAT_ARMOR] -= save;
00717 
00718     return save;
00719 }

Here is the call graph for this function:

void G_Damage gentity_t targ,
gentity_t inflictor,
gentity_t attacker,
vec3_t  dir,
vec3_t  point,
int  damage,
int  dflags,
int  mod
 

Definition at line 821 of file g_combat.c.

References bg_itemlist, CheckArmor(), CheckObeliskAttack(), gentity_s::client, entityShared_t::currentOrigin, gclient_s::damage_armor, gclient_s::damage_blood, gclient_s::damage_from, gclient_s::damage_fromWorld, gclient_s::damage_knockback, gentity_s::die, gentity_s::enemy, ET_MISSILE, entityState_s::eType, EV_POWERUP_BATTLESUIT, gentity_s::flags, G_AddEvent(), g_debugDamage, g_entities, g_friendlyFire, g_gametype, G_InvulnerabilityEffect(), g_knockback, G_Printf(), gclient_t, gentity_t, gitem_s::giTag, GT_CTF, GT_OBELISK, gentity_s::health, vmCvar_t::integer, level_locals_t::intermissionQueued, gclient_s::lasthurt_client, gclient_s::lasthurt_mod, level, max, gentity_s::moverState, gclient_s::noclip, entityState_s::number, OnSameTeam(), gentity_s::pain, gentity_s::parent, playerState_s::persistant, playerState_s::pm_flags, playerState_s::pm_time, point, playerState_s::powerups, gclient_s::ps, gentity_s::r, gentity_s::s, playerState_s::stats, t, gentity_s::takedamage, Team_CheckHurtCarrier(), level_locals_t::time, gentity_s::use, vmCvar_t::value, vec3_t, VectorAdd, VectorCopy, VectorNormalize(), VectorScale, and playerState_s::velocity.

Referenced by Blocked_Door(), Bullet_Fire(), CheckGauntletAttack(), ClientEvents(), G_KillBox(), G_MissileImpact(), G_MoverPush(), G_RadiusDamage(), hurt_touch(), P_WorldEffects(), ShotgunPellet(), target_kill_use(), target_laser_think(), Weapon_LightningFire(), and weapon_railgun_fire().

00822                                                                            {
00823     gclient_t   *client;
00824     int         take;
00825     int         save;
00826     int         asave;
00827     int         knockback;
00828     int         max;
00829 #ifdef MISSIONPACK
00830     vec3_t      bouncedir, impactpoint;
00831 #endif
00832 
00833     if (!targ->takedamage) {
00834         return;
00835     }
00836 
00837     // the intermission has allready been qualified for, so don't
00838     // allow any extra scoring
00839     if ( level.intermissionQueued ) {
00840         return;
00841     }
00842 #ifdef MISSIONPACK
00843     if ( targ->client && mod != MOD_JUICED) {
00844         if ( targ->client->invulnerabilityTime > level.time) {
00845             if ( dir && point ) {
00846                 G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
00847             }
00848             return;
00849         }
00850     }
00851 #endif
00852     if ( !inflictor ) {
00853         inflictor = &g_entities[ENTITYNUM_WORLD];
00854     }
00855     if ( !attacker ) {
00856         attacker = &g_entities[ENTITYNUM_WORLD];
00857     }
00858 
00859     // shootable doors / buttons don't actually have any health
00860     if ( targ->s.eType == ET_MOVER ) {
00861         if ( targ->use && targ->moverState == MOVER_POS1 ) {
00862             targ->use( targ, inflictor, attacker );
00863         }
00864         return;
00865     }
00866 #ifdef MISSIONPACK
00867     if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
00868         return;
00869     }
00870 #endif
00871     // reduce damage by the attacker's handicap value
00872     // unless they are rocket jumping
00873     if ( attacker->client && attacker != targ ) {
00874         max = attacker->client->ps.stats[STAT_MAX_HEALTH];
00875 #ifdef MISSIONPACK
00876         if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
00877             max /= 2;
00878         }
00879 #endif
00880         damage = damage * max / 100;
00881     }
00882 
00883     client = targ->client;
00884 
00885     if ( client ) {
00886         if ( client->noclip ) {
00887             return;
00888         }
00889     }
00890 
00891     if ( !dir ) {
00892         dflags |= DAMAGE_NO_KNOCKBACK;
00893     } else {
00894         VectorNormalize(dir);
00895     }
00896 
00897     knockback = damage;
00898     if ( knockback > 200 ) {
00899         knockback = 200;
00900     }
00901     if ( targ->flags & FL_NO_KNOCKBACK ) {
00902         knockback = 0;
00903     }
00904     if ( dflags & DAMAGE_NO_KNOCKBACK ) {
00905         knockback = 0;
00906     }
00907 
00908     // figure momentum add, even if the damage won't be taken
00909     if ( knockback && targ->client ) {
00910         vec3_t  kvel;
00911         float   mass;
00912 
00913         mass = 200;
00914 
00915         VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
00916         VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
00917 
00918         // set the timer so that the other client can't cancel
00919         // out the movement immediately
00920         if ( !targ->client->ps.pm_time ) {
00921             int     t;
00922 
00923             t = knockback * 2;
00924             if ( t < 50 ) {
00925                 t = 50;
00926             }
00927             if ( t > 200 ) {
00928                 t = 200;
00929             }
00930             targ->client->ps.pm_time = t;
00931             targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00932         }
00933     }
00934 
00935     // check for completely getting out of the damage
00936     if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
00937 
00938         // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
00939         // if the attacker was on the same team
00940 #ifdef MISSIONPACK
00941         if ( mod != MOD_JUICED && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker)  ) {
00942 #else   
00943         if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
00944 #endif
00945             if ( !g_friendlyFire.integer ) {
00946                 return;
00947             }
00948         }
00949 #ifdef MISSIONPACK
00950         if (mod == MOD_PROXIMITY_MINE) {
00951             if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
00952                 return;
00953             }
00954             if (targ == attacker) {
00955                 return;
00956             }
00957         }
00958 #endif
00959 
00960         // check for godmode
00961         if ( targ->flags & FL_GODMODE ) {
00962             return;
00963         }
00964     }
00965 
00966     // battlesuit protects from all radius damage (but takes knockback)
00967     // and protects 50% against all damage
00968     if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
00969         G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
00970         if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
00971             return;
00972         }
00973         damage *= 0.5;
00974     }
00975 
00976     // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
00977     if ( attacker->client && targ != attacker && targ->health > 0
00978             && targ->s.eType != ET_MISSILE
00979             && targ->s.eType != ET_GENERAL) {
00980         if ( OnSameTeam( targ, attacker ) ) {
00981             attacker->client->ps.persistant[PERS_HITS]--;
00982         } else {
00983             attacker->client->ps.persistant[PERS_HITS]++;
00984         }
00985         attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
00986     }
00987 
00988     // always give half damage if hurting self
00989     // calculated after knockback, so rocket jumping works
00990     if ( targ == attacker) {
00991         damage *= 0.5;
00992     }
00993 
00994     if ( damage < 1 ) {
00995         damage = 1;
00996     }
00997     take = damage;
00998     save = 0;
00999 
01000     // save some from armor
01001     asave = CheckArmor (targ, take, dflags);
01002     take -= asave;
01003 
01004     if ( g_debugDamage.integer ) {
01005         G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
01006             targ->health, take, asave );
01007     }
01008 
01009     // add to the damage inflicted on a player this frame
01010     // the total will be turned into screen blends and view angle kicks
01011     // at the end of the frame
01012     if ( client ) {
01013         if ( attacker ) {
01014             client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
01015         } else {
01016             client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
01017         }
01018         client->damage_armor += asave;
01019         client->damage_blood += take;
01020         client->damage_knockback += knockback;
01021         if ( dir ) {
01022             VectorCopy ( dir, client->damage_from );
01023             client->damage_fromWorld = qfalse;
01024         } else {
01025             VectorCopy ( targ->r.currentOrigin, client->damage_from );
01026             client->damage_fromWorld = qtrue;
01027         }
01028     }
01029 
01030     // See if it's the player hurting the emeny flag carrier
01031 #ifdef MISSIONPACK
01032     if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF ) {
01033 #else   
01034     if( g_gametype.integer == GT_CTF) {
01035 #endif
01036         Team_CheckHurtCarrier(targ, attacker);
01037     }
01038 
01039     if (targ->client) {
01040         // set the last client who damaged the target
01041         targ->client->lasthurt_client = attacker->s.number;
01042         targ->client->lasthurt_mod = mod;
01043     }
01044 
01045     // do the damage
01046     if (take) {
01047         targ->health = targ->health - take;
01048         if ( targ->client ) {
01049             targ->client->ps.stats[STAT_HEALTH] = targ->health;
01050         }
01051             
01052         if ( targ->health <= 0 ) {
01053             if ( client )
01054                 targ->flags |= FL_NO_KNOCKBACK;
01055 
01056             if (targ->health < -999)
01057                 targ->health = -999;
01058 
01059             targ->enemy = attacker;
01060             targ->die (targ, inflictor, attacker, take, mod);
01061             return;
01062         } else if ( targ->pain ) {
01063             targ->pain (targ, attacker, take);
01064         }
01065     }
01066 
01067 }

Here is the call graph for this function:

qboolean G_RadiusDamage vec3_t  origin,
gentity_t attacker,
float  damage,
float  radius,
gentity_t ignore,
int  mod
 

Definition at line 1133 of file g_combat.c.

References entityShared_t::absmax, entityShared_t::absmin, CanDamage(), entityShared_t::currentOrigin, DAMAGE_RADIUS, e, G_Damage(), g_entities, gentity_t, i, LogAccuracyHit(), MAX_GENTITIES, NULL, points, qboolean, gentity_s::r, gentity_s::takedamage, trap_EntitiesInBox(), v, vec3_t, VectorLength(), and VectorSubtract.

Referenced by G_ExplodeMissile(), and G_MissileImpact().

01134                                                  {
01135     float       points, dist;
01136     gentity_t   *ent;
01137     int         entityList[MAX_GENTITIES];
01138     int         numListedEntities;
01139     vec3_t      mins, maxs;
01140     vec3_t      v;
01141     vec3_t      dir;
01142     int         i, e;
01143     qboolean    hitClient = qfalse;
01144 
01145     if ( radius < 1 ) {
01146         radius = 1;
01147     }
01148 
01149     for ( i = 0 ; i < 3 ; i++ ) {
01150         mins[i] = origin[i] - radius;
01151         maxs[i] = origin[i] + radius;
01152     }
01153 
01154     numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
01155 
01156     for ( e = 0 ; e < numListedEntities ; e++ ) {
01157         ent = &g_entities[entityList[ e ]];
01158 
01159         if (ent == ignore)
01160             continue;
01161         if (!ent->takedamage)
01162             continue;
01163 
01164         // find the distance from the edge of the bounding box
01165         for ( i = 0 ; i < 3 ; i++ ) {
01166             if ( origin[i] < ent->r.absmin[i] ) {
01167                 v[i] = ent->r.absmin[i] - origin[i];
01168             } else if ( origin[i] > ent->r.absmax[i] ) {
01169                 v[i] = origin[i] - ent->r.absmax[i];
01170             } else {
01171                 v[i] = 0;
01172             }
01173         }
01174 
01175         dist = VectorLength( v );
01176         if ( dist >= radius ) {
01177             continue;
01178         }
01179 
01180         points = damage * ( 1.0 - dist / radius );
01181 
01182         if( CanDamage (ent, origin) ) {
01183             if( LogAccuracyHit( ent, attacker ) ) {
01184                 hitClient = qtrue;
01185             }
01186             VectorSubtract (ent->r.currentOrigin, origin, dir);
01187             // push the center of mass higher than the origin so players
01188             // get knocked into the air more
01189             dir[2] += 24;
01190             G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
01191         }
01192     }
01193 
01194     return hitClient;
01195 }

Here is the call graph for this function:

void GibEntity gentity_t self,
int  killer
 

Definition at line 242 of file g_combat.c.

References gentity_s::activator, gentity_s::classname, entityState_s::eType, EV_GIB_PLAYER, G_AddEvent(), g_entities, G_FreeEntity(), gentity_t, i, gentity_s::inuse, gentity_s::s, strcmp(), and gentity_s::takedamage.

Referenced by body_die(), and player_die().

00242                                               {
00243     gentity_t *ent;
00244     int i;
00245 
00246     //if this entity still has kamikaze
00247     if (self->s.eFlags & EF_KAMIKAZE) {
00248         // check if there is a kamikaze timer around for this owner
00249         for (i = 0; i < MAX_GENTITIES; i++) {
00250             ent = &g_entities[i];
00251             if (!ent->inuse)
00252                 continue;
00253             if (ent->activator != self)
00254                 continue;
00255             if (strcmp(ent->classname, "kamikaze timer"))
00256                 continue;
00257             G_FreeEntity(ent);
00258             break;
00259         }
00260     }
00261     G_AddEvent( self, EV_GIB_PLAYER, killer );
00262     self->takedamage = qfalse;
00263     self->s.eType = ET_INVISIBLE;
00264     self->r.contents = 0;
00265 }

Here is the call graph for this function:

void LookAtKiller gentity_t self,
gentity_t inflictor,
gentity_t attacker
 

Definition at line 217 of file g_combat.c.

References gentity_t, entityState_s::pos, gclient_s::ps, gentity_s::s, playerState_s::stats, trajectory_t::trBase, vec3_t, VectorSubtract, and vectoyaw().

Referenced by player_die().

00217                                                                                 {
00218     vec3_t      dir;
00219     vec3_t      angles;
00220 
00221     if ( attacker && attacker != self ) {
00222         VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
00223     } else if ( inflictor && inflictor != self ) {
00224         VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
00225     } else {
00226         self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
00227         return;
00228     }
00229 
00230     self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
00231 
00232     angles[YAW] = vectoyaw ( dir );
00233     angles[PITCH] = 0; 
00234     angles[ROLL] = 0;
00235 }

Here is the call graph for this function:

void player_die gentity_t self,
gentity_t inflictor,
gentity_t attacker,
int  damage,
int  meansOfDeath
 

Definition at line 439 of file g_combat.c.

References AddScore(), entityState_s::angles, CheckAlmostCapture(), CheckAlmostScored(), gentity_s::client, level_locals_t::clients, Cmd_Score_f(), clientPersistant_t::connected, entityShared_t::currentOrigin, EF_AWARD_ASSIST, EF_AWARD_DEFEND, EF_AWARD_EXCELLENT, EF_AWARD_GAUNTLET, EF_AWARD_IMPRESSIVE, playerState_s::eFlags, EV_DEATH1, EV_OBITUARY, entityState_s::eventParm, G_AddEvent(), g_blood, g_entities, g_gametype, G_LogPrintf(), G_TempEntity(), gclient_t, gentity_t, GIB_HEALTH, GibEntity(), gclient_s::hook, i, vmCvar_t::integer, level_locals_t::intermissiontime, gclient_s::lastkilled_client, gclient_s::lastKillTime, level, LookAtKiller(), level_locals_t::maxclients, memset(), modNames, clientPersistant_t::netname, entityState_s::number, OnSameTeam(), entityState_s::otherEntityNum, entityState_s::otherEntityNum2, gclient_s::pers, playerState_s::persistant, playerState_s::powerups, gclient_s::ps, gentity_s::r, gclient_s::respawnTime, gclient_s::rewardTime, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, clientSession_t::spectatorClient, entityShared_t::svFlags, TEAM_BLUE, Team_FragBonuses(), TEAM_FREE, TEAM_RED, Team_ReturnFlag(), level_locals_t::time, TossClientCubes(), TossClientItems(), trap_LinkEntity(), trap_PointContents(), VectorCopy, playerState_s::viewangles, and Weapon_HookFree().

Referenced by Cmd_Kill_f(), and SetTeam().

00439                                                                                                             {
00440     gentity_t   *ent;
00441     int         anim;
00442     int         contents;
00443     int         killer;
00444     int         i;
00445     char        *killerName, *obit;
00446 
00447     if ( self->client->ps.pm_type == PM_DEAD ) {
00448         return;
00449     }
00450 
00451     if ( level.intermissiontime ) {
00452         return;
00453     }
00454 
00455     // check for an almost capture
00456     CheckAlmostCapture( self, attacker );
00457     // check for a player that almost brought in cubes
00458     CheckAlmostScored( self, attacker );
00459 
00460     if (self->client && self->client->hook) {
00461         Weapon_HookFree(self->client->hook);
00462     }
00463 #ifdef MISSIONPACK
00464     if ((self->client->ps.eFlags & EF_TICKING) && self->activator) {
00465         self->client->ps.eFlags &= ~EF_TICKING;
00466         self->activator->think = G_FreeEntity;
00467         self->activator->nextthink = level.time;
00468     }
00469 #endif
00470     self->client->ps.pm_type = PM_DEAD;
00471 
00472     if ( attacker ) {
00473         killer = attacker->s.number;
00474         if ( attacker->client ) {
00475             killerName = attacker->client->pers.netname;
00476         } else {
00477             killerName = "<non-client>";
00478         }
00479     } else {
00480         killer = ENTITYNUM_WORLD;
00481         killerName = "<world>";
00482     }
00483 
00484     if ( killer < 0 || killer >= MAX_CLIENTS ) {
00485         killer = ENTITYNUM_WORLD;
00486         killerName = "<world>";
00487     }
00488 
00489     if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
00490         obit = "<bad obituary>";
00491     } else {
00492         obit = modNames[ meansOfDeath ];
00493     }
00494 
00495     G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", 
00496         killer, self->s.number, meansOfDeath, killerName, 
00497         self->client->pers.netname, obit );
00498 
00499     // broadcast the death event to everyone
00500     ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
00501     ent->s.eventParm = meansOfDeath;
00502     ent->s.otherEntityNum = self->s.number;
00503     ent->s.otherEntityNum2 = killer;
00504     ent->r.svFlags = SVF_BROADCAST; // send to everyone
00505 
00506     self->enemy = attacker;
00507 
00508     self->client->ps.persistant[PERS_KILLED]++;
00509 
00510     if (attacker && attacker->client) {
00511         attacker->client->lastkilled_client = self->s.number;
00512 
00513         if ( attacker == self || OnSameTeam (self, attacker ) ) {
00514             AddScore( attacker, self->r.currentOrigin, -1 );
00515         } else {
00516             AddScore( attacker, self->r.currentOrigin, 1 );
00517 
00518             if( meansOfDeath == MOD_GAUNTLET ) {
00519                 
00520                 // play humiliation on player
00521                 attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
00522 
00523                 // add the sprite over the player's head
00524                 attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00525                 attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
00526                 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00527 
00528                 // also play humiliation on target
00529                 self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
00530             }
00531 
00532             // check for two kills in a short amount of time
00533             // if this is close enough to the last kill, give a reward sound
00534             if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
00535                 // play excellent on player
00536                 attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
00537 
00538                 // add the sprite over the player's head
00539                 attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00540                 attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
00541                 attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00542             }
00543             attacker->client->lastKillTime = level.time;
00544 
00545         }
00546     } else {
00547         AddScore( self, self->r.currentOrigin, -1 );
00548     }
00549 
00550     // Add team bonuses
00551     Team_FragBonuses(self, inflictor, attacker);
00552 
00553     // if I committed suicide, the flag does not fall, it returns.
00554     if (meansOfDeath == MOD_SUICIDE) {
00555         if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {      // only happens in One Flag CTF
00556             Team_ReturnFlag( TEAM_FREE );
00557             self->client->ps.powerups[PW_NEUTRALFLAG] = 0;
00558         }
00559         else if ( self->client->ps.powerups[PW_REDFLAG] ) {     // only happens in standard CTF
00560             Team_ReturnFlag( TEAM_RED );
00561             self->client->ps.powerups[PW_REDFLAG] = 0;
00562         }
00563         else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {    // only happens in standard CTF
00564             Team_ReturnFlag( TEAM_BLUE );
00565             self->client->ps.powerups[PW_BLUEFLAG] = 0;
00566         }
00567     }
00568 
00569     // if client is in a nodrop area, don't drop anything (but return CTF flags!)
00570     contents = trap_PointContents( self->r.currentOrigin, -1 );
00571     if ( !( contents & CONTENTS_NODROP )) {
00572         TossClientItems( self );
00573     }
00574     else {
00575         if ( self->client->ps.powerups[PW_NEUTRALFLAG] ) {      // only happens in One Flag CTF
00576             Team_ReturnFlag( TEAM_FREE );
00577         }
00578         else if ( self->client->ps.powerups[PW_REDFLAG] ) {     // only happens in standard CTF
00579             Team_ReturnFlag( TEAM_RED );
00580         }
00581         else if ( self->client->ps.powerups[PW_BLUEFLAG] ) {    // only happens in standard CTF
00582             Team_ReturnFlag( TEAM_BLUE );
00583         }
00584     }
00585 #ifdef MISSIONPACK
00586     TossClientPersistantPowerups( self );
00587     if( g_gametype.integer == GT_HARVESTER ) {
00588         TossClientCubes( self );
00589     }
00590 #endif
00591 
00592     Cmd_Score_f( self );        // show scores
00593     // send updated scores to any clients that are following this one,
00594     // or they would get stale scoreboards
00595     for ( i = 0 ; i < level.maxclients ; i++ ) {
00596         gclient_t   *client;
00597 
00598         client = &level.clients[i];
00599         if ( client->pers.connected != CON_CONNECTED ) {
00600             continue;
00601         }
00602         if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
00603             continue;
00604         }
00605         if ( client->sess.spectatorClient == self->s.number ) {
00606             Cmd_Score_f( g_entities + i );
00607         }
00608     }
00609 
00610     self->takedamage = qtrue;   // can still be gibbed
00611 
00612     self->s.weapon = WP_NONE;
00613     self->s.powerups = 0;
00614     self->r.contents = CONTENTS_CORPSE;
00615 
00616     self->s.angles[0] = 0;
00617     self->s.angles[2] = 0;
00618     LookAtKiller (self, inflictor, attacker);
00619 
00620     VectorCopy( self->s.angles, self->client->ps.viewangles );
00621 
00622     self->s.loopSound = 0;
00623 
00624     self->r.maxs[2] = -8;
00625 
00626     // don't allow respawn until the death anim is done
00627     // g_forcerespawn may force spawning at some later time
00628     self->client->respawnTime = level.time + 1700;
00629 
00630     // remove powerups
00631     memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );
00632 
00633     // never gib in a nodrop
00634     if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) {
00635         // gib death
00636         GibEntity( self, killer );
00637     } else {
00638         // normal death
00639         static int i;
00640 
00641         switch ( i ) {
00642         case 0:
00643             anim = BOTH_DEATH1;
00644             break;
00645         case 1:
00646             anim = BOTH_DEATH2;
00647             break;
00648         case 2:
00649         default:
00650             anim = BOTH_DEATH3;
00651             break;
00652         }
00653 
00654         // for the no-blood option, we need to prevent the health
00655         // from going to gib level
00656         if ( self->health <= GIB_HEALTH ) {
00657             self->health = GIB_HEALTH+1;
00658         }
00659 
00660         self->client->ps.legsAnim = 
00661             ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
00662         self->client->ps.torsoAnim = 
00663             ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
00664 
00665         G_AddEvent( self, EV_DEATH1 + i, killer );
00666 
00667         // the body can still be gibbed
00668         self->die = body_die;
00669 
00670         // globally cycle through the different death animations
00671         i = ( i + 1 ) % 3;
00672 
00673 #ifdef MISSIONPACK
00674         if (self->s.eFlags & EF_KAMIKAZE) {
00675             Kamikaze_DeathTimer( self );
00676         }
00677 #endif
00678     }
00679 
00680     trap_LinkEntity (self);
00681 
00682 }

Here is the call graph for this function:

int RaySphereIntersections vec3_t  origin,
float  radius,
vec3_t