codemp/game/g_combat.c File Reference

#include "b_local.h"
#include "bg_saga.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Defines

#define DEATH_ALERT_RADIUS   512
#define DEATH_ALERT_SOUND_RADIUS   512

Functions

int G_ShipSurfaceForSurfName (const char *surfaceName)
qboolean G_FlyVehicleDestroySurface (gentity_t *veh, int surface)
void G_VehicleSetDamageLocFlags (gentity_t *veh, int impactDir, int deathPoint)
void G_VehUpdateShields (gentity_t *targ)
void G_LetGoOfWall (gentity_t *ent)
void BG_ClearRocketLock (playerState_t *ps)
void BotDamageNotification (gclient_t *bot, gentity_t *attacker)
void ThrowSaberToAttacker (gentity_t *self, gentity_t *attacker)
void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
qboolean G_HeavyMelee (gentity_t *attacker)
int G_GetHitLocation (gentity_t *target, vec3_t ppoint)
void ExplodeDeath (gentity_t *self)
void ScorePlum (gentity_t *ent, vec3_t origin, int score)
void AddScore (gentity_t *ent, vec3_t origin, int score)
void TossClientWeapon (gentity_t *self, vec3_t direction, float speed)
void TossClientItems (gentity_t *self)
void LookAtKiller (gentity_t *self, gentity_t *inflictor, gentity_t *attacker)
void GibEntity (gentity_t *self, int killer)
void BodyRid (gentity_t *ent)
void body_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
void CheckAlmostCapture (gentity_t *self, gentity_t *attacker)
qboolean G_InKnockDown (playerState_t *ps)
int G_PickDeathAnim (gentity_t *self, vec3_t point, int damage, int mod, int hitLoc)
gentity_tG_GetJediMaster (void)
void G_AlertTeam (gentity_t *victim, gentity_t *attacker, float radius, float soundDist)
void G_DeathAlert (gentity_t *victim, gentity_t *attacker)
void DeathFX (gentity_t *ent)
void G_CheckVictoryScript (gentity_t *self)
void G_AddPowerDuelScore (int team, int score)
void G_AddPowerDuelLoserScore (int team, int score)
void AI_DeleteSelfFromGroup (gentity_t *self)
void AI_GroupMemberKilled (gentity_t *self)
void Boba_FlyStop (gentity_t *self)
qboolean Jedi_WaitingAmbush (gentity_t *self)
void CheckExitRules (void)
void Rancor_DropVictim (gentity_t *self)
void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath)
int CheckArmor (gentity_t *ent, int damage, int dflags)
void G_ApplyKnockback (gentity_t *targ, vec3_t newDir, float knockback)
int RaySphereIntersections (vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2])
void G_GetDismemberLoc (gentity_t *self, vec3_t boltPoint, int limbType)
void G_GetDismemberBolt (gentity_t *self, vec3_t boltPoint, int limbType)
void LimbTouch (gentity_t *self, gentity_t *other, trace_t *trace)
void LimbThink (gentity_t *ent)
qboolean BG_GetRootSurfNameWithVariant (void *ghoul2, const char *rootSurfName, char *returnSurfName, int returnSize)
void G_Dismember (gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath)
void DismembermentTest (gentity_t *self)
void DismembermentByNum (gentity_t *self, int num)
int G_GetHitQuad (gentity_t *self, vec3_t hitloc)
void UpdateClientRenderBolts (gentity_t *self, vec3_t renderOrigin, vec3_t renderAngles)
qboolean G_GetHitLocFromSurfName (gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod)
void G_CheckForDismemberment (gentity_t *ent, gentity_t *enemy, vec3_t point, int damage, int deathAnim, qboolean postDeath)
void G_LocationBasedDamageModifier (gentity_t *ent, vec3_t point, int mod, int dflags, int *damage)
qboolean G_ThereIsAMaster (void)
void G_Knockdown (gentity_t *victim)
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 CanDamage (gentity_t *targ, vec3_t origin)
qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, gentity_t *missile, int mod)

Variables

qboolean g_dontPenalizeTeam
char * modNames [MOD_MAX]
stringID_table_t animTable [MAX_ANIMATIONS+1]
qboolean g_dontFrickinCheck
qboolean g_endPDuel
qboolean g_noPDuelCheck
char * hitLocName [HL_MAX]
int gGAvoidDismember = 0
qboolean gSiegeRoundBegun
int gPainMOD = 0
int gPainHitLoc = -1
vec3_t gPainPoint


Define Documentation

#define DEATH_ALERT_RADIUS   512
 

Definition at line 1865 of file g_combat.c.

Referenced by G_DeathAlert().

#define DEATH_ALERT_SOUND_RADIUS   512
 

Definition at line 1866 of file g_combat.c.

Referenced by G_DeathAlert().


Function Documentation

void AddScore gentity_t ent,
vec3_t  origin,
int  score
 

Definition at line 436 of file g_combat.c.

References CalculateRanks(), gentity_s::client, g_dontPenalizeTeam, g_gametype, gentity_t, GT_TEAM, vmCvar_t::integer, level, PERS_SCORE, PERS_TEAM, playerState_s::persistant, gclient_s::ps, level_locals_t::teamScores, vec3_t, and level_locals_t::warmupTime.

Referenced by AddSiegeWinningTeamPoints(), BroadcastObjectiveCompletion(), player_die(), Team_FragBonuses(), Team_TouchEnemyFlag(), Team_TouchOurFlag(), Use_Target_Escapetrig(), and Use_Target_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 }

void AI_DeleteSelfFromGroup gentity_t self  ) 
 

Definition at line 602 of file NPC_AI_Utils.c.

References AI_DeleteGroupMember(), gentity_t, gNPC_t::group, AIGroupInfo_s::member, gentity_s::NPC, AIGroupMember_s::number, entityState_s::number, AIGroupInfo_s::numGroup, and gentity_s::s.

Referenced by player_die().

00603 {
00604         int i;
00605 
00606         //FIXME: if killed, keep track of how many in group killed?  To affect morale?
00607         for ( i = 0; i < self->NPC->group->numGroup; i++ )
00608         {
00609                 if ( self->NPC->group->member[i].number == self->s.number )
00610                 {
00611                         AI_DeleteGroupMember( self->NPC->group, i );
00612                         return;
00613                 }
00614         }
00615 }

void AI_GroupMemberKilled gentity_t self  ) 
 

Definition at line 620 of file NPC_AI_Utils.c.

References AEL_DANGER_GREAT, AIGroupInfo_t, AIGroupInfo_s::commander, gNPC_t::currentAim, entityShared_t::currentOrigin, AIGroupInfo_s::enemy, g_entities, gentity_t, gNPC_t::group, AIGroupInfo_s::member, AIGroupInfo_s::moraleAdjust, gentity_s::NPC, AIGroupMember_s::number, AIGroupInfo_s::numGroup, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_ENSIGN, AIGroupInfo_s::speechDebounceTime, ST_AggressionAdjust(), ST_MarkToCover(), and ST_StartFlee().

Referenced by player_die().

00621 {
00622         AIGroupInfo_t *group = self->NPC->group;
00623         gentity_t       *member;
00624         qboolean        noflee = qfalse;
00625         int                     i;
00626 
00627         if ( !group )
00628         {//what group?
00629                 return;
00630         }
00631         if ( !self || !self->NPC || self->NPC->rank < RANK_ENSIGN )
00632         {//I'm not an officer, let's not really care for now
00633                 return;
00634         }
00635         //temporarily drop group morale for a few seconds
00636         group->moraleAdjust -= self->NPC->rank;
00637         //go through and drop aggression on my teammates (more cover, worse aim)
00638         for ( i = 0; i < group->numGroup; i++ )
00639         {
00640                 member = &g_entities[group->member[i].number];
00641                 if ( member == self )
00642                 {
00643                         continue;
00644                 }
00645                 if ( member->NPC->rank > RANK_ENSIGN )
00646                 {//officers do not panic
00647                         noflee = qtrue;
00648                 }
00649                 else
00650                 {
00651                         ST_AggressionAdjust( member, -1 );
00652                         member->NPC->currentAim -= Q_irand( 0, 10 );//Q_irand( 0, 2);//drop their aim accuracy
00653                 }
00654         }
00655         //okay, if I'm the group commander, make everyone else flee
00656         if ( group->commander != self )
00657         {//I'm not the commander... hmm, should maybe a couple flee... maybe those near me?
00658                 return;
00659         }
00660         //now see if there is another of sufficient rank to keep them from fleeing
00661         if ( !noflee )
00662         {
00663                 self->NPC->group->speechDebounceTime = 0;
00664                 for ( i = 0; i < group->numGroup; i++ )
00665                 {
00666                         member = &g_entities[group->member[i].number];
00667                         if ( member == self )
00668                         {
00669                                 continue;
00670                         }
00671                         if ( member->NPC->rank < RANK_ENSIGN )
00672                         {//grunt
00673                                 if ( group->enemy && DistanceSquared( member->r.currentOrigin, group->enemy->r.currentOrigin ) < 65536/*256*256*/ )
00674                                 {//those close to enemy run away!
00675                                         ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00676                                 }
00677                                 else if ( DistanceSquared( member->r.currentOrigin, self->r.currentOrigin ) < 65536/*256*256*/ )
00678                                 {//those close to me run away!
00679                                         ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00680                                 }
00681                                 else
00682                                 {//else, maybe just a random chance
00683                                         if ( Q_irand( 0, self->NPC->rank ) > member->NPC->rank )
00684                                         {//lower rank they are, higher rank I am, more likely they are to flee
00685                                                 ST_StartFlee( member, group->enemy, member->r.currentOrigin, AEL_DANGER_GREAT, 3000, 5000 );
00686                                         }
00687                                         else
00688                                         {
00689                                                 ST_MarkToCover( member );
00690                                         }
00691                                 }
00692                                 member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00693                         }
00694                         member->NPC->currentAim -= Q_irand( 1, 15 ); //Q_irand( 1, 3 );//drop their aim accuracy even more
00695                 }
00696         }
00697 }

void BG_ClearRocketLock playerState_t ps  ) 
 

Definition at line 5751 of file bg_pmove.c.

References ENTITYNUM_NONE, playerState_t, playerState_s::rocketLastValidTime, playerState_s::rocketLockIndex, playerState_s::rocketLockTime, and playerState_s::rocketTargetTime.

Referenced by player_die(), and PM_BeginWeaponChange().

05752 {
05753         if ( ps )
05754         {
05755                 ps->rocketLockIndex = ENTITYNUM_NONE;
05756                 ps->rocketLastValidTime = 0;
05757                 ps->rocketLockTime = -1;
05758                 ps->rocketTargetTime = 0;
05759         }
05760 }

qboolean BG_GetRootSurfNameWithVariant void *  ghoul2,
const char *  rootSurfName,
char *  returnSurfName,
int  returnSize
 

Definition at line 101 of file bg_g2_utils.c.

References Com_sprintf(), MAX_VARIANTS, Q_strncpyz(), qboolean, qfalse, qtrue, and trap_G2API_GetSurfaceRenderStatus().

Referenced by G_Dismember().

00102 {
00103         if ( !ghoul2 || !trap_G2API_GetSurfaceRenderStatus( ghoul2, 0, rootSurfName ) )
00104         {//see if the basic name without variants is on
00105                 Q_strncpyz( returnSurfName, rootSurfName, returnSize );
00106                 return qtrue;
00107         }
00108         else
00109         {//check variants
00110                 int i;
00111                 for ( i = 0; i < MAX_VARIANTS; i++ )
00112                 {
00113                         Com_sprintf( returnSurfName, returnSize, "%s%c", rootSurfName, 'a'+i );
00114                         if ( !trap_G2API_GetSurfaceRenderStatus( ghoul2, 0, returnSurfName ) )
00115                         {
00116                                 return qtrue;
00117                         }
00118                 }
00119         }
00120         Q_strncpyz( returnSurfName, rootSurfName, returnSize );
00121         return qfalse;
00122 }

void Boba_FlyStop gentity_t self  ) 
 

Definition at line 367 of file NPC_AI_Jedi.c.

00368 {
00369         self->client->ps.gravity = g_gravity.value;
00370         if ( self->NPC )
00371         {
00372                 self->NPC->aiFlags &= ~NPCAI_CUSTOM_GRAVITY;
00373         }
00374         self->client->ps.eFlags2 &= ~EF2_FLYING;
00375         self->client->jetPackTime = 0;
00376         //stop jet loop sound
00377         self->s.loopSound = 0;
00378         if ( self->NPC )
00379         {
00380                 self->count = 0; // SEEKER shot ammo count
00381                 TIMER_Set( self, "jetRecharge", Q_irand( 1000, 5000 ) );
00382                 TIMER_Set( self, "jumpChaseDebounce", Q_irand( 500, 2000 ) );
00383         }
00384 }

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

Definition at line 685 of file g_combat.c.

References BodyRid(), gentity_s::client, entityShared_t::currentOrigin, EF_DISINTEGRATION, playerState_s::eFlags, entityState_s::eFlags, ET_NPC, entityState_s::eType, G_FreeEntity(), gentity_t, GIB_HEALTH, gentity_s::health, playerState_s::lastHitLoc, level, MOD_CRUSH, MOD_FALLING, MOD_LAVA, MOD_SLIME, MOD_SUICIDE, MOD_TARGET_LASER, MOD_TELEFRAG, MOD_TRIGGER_HURT, MOD_UNKNOWN, MOD_WATER, gentity_s::nextthink, playerState_s::origin, entityState_s::origin2, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gclient_s::respawnTime, gentity_s::s, gentity_s::think, level_locals_t::time, playerState_s::torsoTimer, and VectorCopy.

Referenced by player_die().

00685                                                                                                           {
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 }

void BodyRid gentity_t ent  ) 
 

Definition at line 674 of file g_combat.c.

References gentity_t, gentity_s::physicsObject, qfalse, and trap_UnlinkEntity().

Referenced by body_die().

00675 {
00676         trap_UnlinkEntity( ent );
00677         ent->physicsObject = qfalse;
00678 }

void BotDamageNotification gclient_t bot,
gentity_t attacker
 

Definition at line 1861 of file ai_main.c.

References bot_state_t, botstates, bot_state_s::client, gentity_s::client, playerState_s::clientNum, bot_state_s::currentEnemy, ENEMY_FORGET_MS, bot_state_s::enemySeenTime, g_entities, gclient_t, gentity_t, bot_state_s::lastAttacked, bot_state_s::lastHurt, level, MAX_CLIENTS, NULL, entityState_s::number, PassLovedOneCheck(), PassStandardEnemyChecks(), gclient_s::ps, gentity_s::s, and level_locals_t::time.

Referenced by G_Damage().

01862 {
01863         bot_state_t *bs;
01864         bot_state_t *bs_a;
01865         int i;
01866 
01867         if (!bot || !attacker || !attacker->client)
01868         {
01869                 return;
01870         }
01871 
01872         if (bot->ps.clientNum >= MAX_CLIENTS)
01873         { //an NPC.. do nothing for them.
01874                 return;
01875         }
01876 
01877         if (attacker->s.number >= MAX_CLIENTS)
01878         { //if attacker is an npc also don't care I suppose.
01879                 return;
01880         }
01881 
01882         bs_a = botstates[attacker->s.number];
01883 
01884         if (bs_a)
01885         { //if the client attacking us is a bot as well
01886                 bs_a->lastAttacked = &g_entities[bot->ps.clientNum];
01887                 i = 0;
01888 
01889                 while (i < MAX_CLIENTS)
01890                 {
01891                         if (botstates[i] &&
01892                                 i != bs_a->client &&
01893                                 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01894                         {
01895                                 botstates[i]->lastAttacked = NULL;
01896                         }
01897 
01898                         i++;
01899                 }
01900         }
01901         else //got attacked by a real client, so no one gets rights to lastAttacked
01902         {
01903                 i = 0;
01904 
01905                 while (i < MAX_CLIENTS)
01906                 {
01907                         if (botstates[i] &&
01908                                 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01909                         {
01910                                 botstates[i]->lastAttacked = NULL;
01911                         }
01912 
01913                         i++;
01914                 }
01915         }
01916 
01917         bs = botstates[bot->ps.clientNum];
01918 
01919         if (!bs)
01920         {
01921                 return;
01922         }
01923 
01924         bs->lastHurt = attacker;
01925 
01926         if (bs->currentEnemy)
01927         { //we don't care about the guy attacking us if we have an enemy already
01928                 return;
01929         }
01930 
01931         if (!PassStandardEnemyChecks(bs, attacker))
01932         { //the person that hurt us is not a valid enemy
01933                 return;
01934         }
01935 
01936         if (PassLovedOneCheck(bs, attacker))
01937         { //the person that hurt us is the one we love!
01938                 bs->currentEnemy = attacker;
01939                 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
01940         }
01941 }

qboolean CanDamage gentity_t targ,
vec3_t  origin
 

Definition at line 5510 of file g_combat.c.

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

Referenced by G_RadiusDamage().

05510                                                     {
05511         vec3_t  dest;
05512         trace_t tr;
05513         vec3_t  midpoint;
05514 
05515         // use the midpoint of the bounds instead of the origin, because
05516         // bmodels may have their origin is 0,0,0
05517         VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
05518         VectorScale (midpoint, 0.5, midpoint);
05519 
05520         VectorCopy (midpoint, dest);
05521         trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05522         if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
05523                 return qtrue;
05524 
05525         // this should probably check in the plane of projection, 
05526         // rather than in world coordinate, and also include Z
05527         VectorCopy (midpoint, dest);
05528         dest[0] += 15.0;
05529         dest[1] += 15.0;
05530         trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05531         if (tr.fraction == 1.0)
05532                 return qtrue;
05533 
05534         VectorCopy (midpoint, dest);
05535         dest[0] += 15.0;
05536         dest[1] -= 15.0;
05537         trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05538         if (tr.fraction == 1.0)
05539                 return qtrue;
05540 
05541         VectorCopy (midpoint, dest);
05542         dest[0] -= 15.0;
05543         dest[1] += 15.0;
05544         trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05545         if (tr.fraction == 1.0)
05546                 return qtrue;
05547 
05548         VectorCopy (midpoint, dest);
05549         dest[0] -= 15.0;
05550         dest[1] -= 15.0;
05551         trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
05552         if (tr.fraction == 1.0)
05553                 return qtrue;
05554 
05555 
05556         return qfalse;
05557 }

void CheckAlmostCapture gentity_t self,
gentity_t attacker
 

Definition at line 805 of file g_combat.c.

References gentity_s::client, FL_DROPPED_ITEM, gentity_s::flags, FOFS, G_Find(), g_gametype, gentity_t, GT_CTF, GT_CTY, vmCvar_t::integer, NULL, entityState_s::origin, playerState_s::origin, PERS_PLAYEREVENTS, playerState_s::persistant, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_NEUTRALFLAG, PW_REDFLAG, gentity_s::r, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, SVF_NOCLIENT, entityShared_t::svFlags, TEAM_BLUE, vec3_t, and VectorSubtract.

Referenced by player_die().

00805                                                                 {
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 }

int CheckArmor gentity_t ent,
int  damage,
int  dflags
 

Definition at line 2894 of file g_combat.c.

References ARMOR_PROTECTION, ARMOR_REDUCTION_FACTOR, ceil(), CLASS_VEHICLE, gentity_s::client, client, DAMAGE_HALF_ABSORB, DAMAGE_HALF_ARMOR_REDUCTION, DAMAGE_NO_ARMOR, playerState_s::electrifyTime, gclient_t, gentity_t, level, gentity_s::m_pVehicle, gclient_s::NPC_class, gclient_s::ps, STAT_ARMOR, playerState_s::stats, and level_locals_t::time.

Referenced by G_Damage().

02895 {
02896         gclient_t       *client;
02897         int                     save;
02898         int                     count;
02899 
02900         if (!damage)
02901                 return 0;
02902 
02903         client = ent->client;
02904 
02905         if (!client)
02906                 return 0;
02907 
02908         if (dflags & DAMAGE_NO_ARMOR)
02909                 return 0;
02910 
02911         if ( client->NPC_class == CLASS_VEHICLE
02912                 && ent->m_pVehicle
02913                 && ent->client->ps.electrifyTime > level.time )
02914         {//ion-cannon has disabled this ship's shields, take damage on hull!
02915                 return 0;
02916         }
02917         // armor
02918         count = client->ps.stats[STAT_ARMOR];
02919 
02920         if (dflags & DAMAGE_HALF_ABSORB)
02921         {       // Half the damage gets absorbed by the shields, rather than 100%
02922                 save = ceil( damage * ARMOR_PROTECTION );
02923         }
02924         else
02925         {       // All the damage gets absorbed by the shields.
02926                 save = damage;
02927         }
02928 
02929         // save is the most damage that the armor is elibigle to protect, of course, but it's limited by the total armor.
02930         if (save >= count)
02931                 save = count;
02932 
02933         if (!save)
02934                 return 0;
02935 
02936         if (dflags & DAMAGE_HALF_ARMOR_REDUCTION)               // Armor isn't whittled so easily by sniper shots.
02937         {
02938                 client->ps.stats[STAT_ARMOR] -= (int)(save*ARMOR_REDUCTION_FACTOR);
02939         }
02940         else
02941         {
02942                 client->ps.stats[STAT_ARMOR] -= save;
02943         }
02944 
02945         return save;
02946 }

void CheckExitRules void   ) 
 

Definition at line 2572 of file g_main.c.

References BeginIntermission(), CheckIntermissionExit(), gentity_s::client, level_locals_t::clients, Com_Printf(), CON_CONNECTED, clientPersistant_t::connected, d_powerDuelPrint, g_capturelimit, g_duel_fraglimit, g_endPDuel, g_entities, g_fraglimit, g_gametype, G_GetStringEdString(), g_maxclients, g_timelimit, gclient_t, gDoSlowMoDuel, gDuelExit, gEscapeTime, gEscaping, GT_CTF, GT_DUEL, GT_POWERDUEL, GT_SIEGE, gentity_s::health, vmCvar_t::integer, INTERMISSION_DELAY_TIME, level_locals_t::intermissionQueued, level_locals_t::intermissiontime, gentity_s::inuse, level, LogExit(), MAX_CLIENTS, clientPersistant_t::netname, level_locals_t::numPlayingClients, gclient_s::pers, PERS_SCORE, playerState_s::persistant, playerState_s::pm_flags, PMF_FOLLOW, gclient_s::ps, qboolean, qfalse, qtrue, S_COLOR_WHITE, ScoreIsTied(), gclient_s::sess, clientSession_t::sessionTeam, level_locals_t::startTime, TEAM_BLUE, TEAM_FREE, TEAM_RED, TEAM_SPECTATOR, level_locals_t::teamScores, level_locals_t::time, trap_SendServerCommand(), va(), level_locals_t::warmupTime, and clientSession_t::wins.

Referenced by CalculateRanks(), G_RunFrame(), and player_die().

02572                             {
02573         int                     i;
02574         gclient_t       *cl;
02575         char *sKillLimit;
02576         qboolean printLimit = qtrue;
02577         // if at the intermission, wait for all non-bots to
02578         // signal ready, then go to next level
02579         if ( level.intermissiontime ) {
02580                 CheckIntermissionExit ();
02581                 return;
02582         }
02583 
02584         if (gDoSlowMoDuel)
02585         { //don't go to intermission while in slow motion
02586                 return;
02587         }
02588 
02589         if (gEscaping)
02590         {
02591                 int i = 0;
02592                 int numLiveClients = 0;
02593 
02594                 while (i < MAX_CLIENTS)
02595                 {
02596                         if (g_entities[i].inuse && g_entities[i].client && g_entities[i].health > 0)
02597                         {
02598                                 if (g_entities[i].client->sess.sessionTeam != TEAM_SPECTATOR &&
02599                                         !(g_entities[i].client->ps.pm_flags & PMF_FOLLOW))
02600                                 {
02601                                         numLiveClients++;
02602                                 }
02603                         }
02604 
02605                         i++;
02606                 }
02607                 if (gEscapeTime < level.time)
02608                 {
02609                         gEscaping = qfalse;
02610                         LogExit( "Escape time ended." );
02611                         return;
02612                 }
02613                 if (!numLiveClients)
02614                 {
02615                         gEscaping = qfalse;
02616                         LogExit( "Everyone failed to escape." );
02617                         return;
02618                 }
02619         }
02620 
02621         if ( level.intermissionQueued ) {
02622                 //int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
02623                 int time = INTERMISSION_DELAY_TIME;
02624                 if ( level.time - level.intermissionQueued >= time ) {
02625                         level.intermissionQueued = 0;
02626                         BeginIntermission();
02627                 }
02628                 return;
02629         }
02630 
02631         /*
02632         if (g_gametype.integer == GT_POWERDUEL)
02633         {
02634                 if (level.numPlayingClients < 3)
02635                 {
02636                         if (!level.intermissiontime)
02637                         {
02638                                 if (d_powerDuelPrint.integer)
02639                                 {
02640                                         Com_Printf("POWERDUEL WIN CONDITION: Duel forfeit (1)\n");
02641                                 }
02642                                 LogExit("Duel forfeit.");
02643                                 return;
02644                         }
02645                 }
02646         }
02647         */
02648 
02649         // check for sudden death
02650         if (g_gametype.integer != GT_SIEGE)
02651         {
02652                 if ( ScoreIsTied() ) {
02653                         // always wait for sudden death
02654                         if ((g_gametype.integer != GT_DUEL) || !g_timelimit.integer)
02655                         {
02656                                 if (g_gametype.integer != GT_POWERDUEL)
02657                                 {
02658                                         return;
02659                                 }
02660                         }
02661                 }
02662         }
02663 
02664         if (g_gametype.integer != GT_SIEGE)
02665         {
02666                 if ( g_timelimit.integer && !level.warmupTime ) {
02667                         if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
02668 //                              trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
02669                                 trap_SendServerCommand( -1, va("print \"%s.\n\"",G_GetStringEdString("MP_SVGAME", "TIMELIMIT_HIT")));
02670                                 if (d_powerDuelPrint.integer)
02671                                 {
02672                                         Com_Printf("POWERDUEL WIN CONDITION: Timelimit hit (1)\n");
02673                                 }
02674                                 LogExit( "Timelimit hit." );
02675                                 return;
02676                         }
02677                 }
02678         }
02679 
02680         if (g_gametype.integer == GT_POWERDUEL && level.numPlayingClients >= 3)
02681         {
02682                 if (g_endPDuel)
02683                 {
02684                         g_endPDuel = qfalse;
02685                         LogExit("Powerduel ended.");
02686                 }
02687 
02688                 //yeah, this stuff was completely insane.
02689                 /*
02690                 int duelists[3];
02691                 duelists[0] = level.sortedClients[0];
02692                 duelists[1] = level.sortedClients[1];
02693                 duelists[2] = level.sortedClients[2];
02694 
02695                 if (duelists[0] != -1 &&
02696                         duelists[1] != -1 &&
02697                         duelists[2] != -1)
02698                 {
02699                         if (!g_entities[duelists[0]].inuse ||
02700                                 !g_entities[duelists[0]].client ||
02701                                 g_entities[duelists[0]].client->ps.stats[STAT_HEALTH] <= 0 ||
02702                                 g_entities[duelists[0]].client->sess.sessionTeam != TEAM_FREE)
02703                         { //The lone duelist lost, give the other two wins (if applicable) and him a loss
02704                                 if (g_entities[duelists[0]].inuse &&
02705                                         g_entities[duelists[0]].client)
02706                                 {
02707                                         g_entities[duelists[0]].client->sess.losses++;
02708                                         ClientUserinfoChanged(duelists[0]);
02709                                 }
02710                                 if (g_entities[duelists[1]].inuse &&
02711                                         g_entities[duelists[1]].client)
02712                                 {
02713                                         if (g_entities[duelists[1]].client->ps.stats[STAT_HEALTH] > 0 &&
02714                                                 g_entities[duelists[1]].client->sess.sessionTeam == TEAM_FREE)
02715                                         {
02716                                                 g_entities[duelists[1]].client->sess.wins++;
02717                                         }
02718                                         else
02719                                         {
02720                                                 g_entities[duelists[1]].client->sess.losses++;
02721                                         }
02722                                         ClientUserinfoChanged(duelists[1]);
02723                                 }
02724                                 if (g_entities[duelists[2]].inuse &&
02725                                         g_entities[duelists[2]].client)
02726                                 {
02727                                         if (g_entities[duelists[2]].client->ps.stats[STAT_HEALTH] > 0 &&
02728                                                 g_entities[duelists[2]].client->sess.sessionTeam == TEAM_FREE)
02729                                         {
02730                                                 g_entities[duelists[2]].client->sess.wins++;
02731                                         }
02732                                         else
02733                                         {
02734                                                 g_entities[duelists[2]].client->sess.losses++;
02735                                         }
02736                                         ClientUserinfoChanged(duelists[2]);
02737                                 }
02738 
02739                                 //Will want to parse indecies for two out at some point probably
02740                                 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", duelists[1] ) );
02741 
02742                                 if (d_powerDuelPrint.integer)
02743                                 {
02744                                         Com_Printf("POWERDUEL WIN CONDITION: Coupled duelists won (1)\n");
02745                                 }
02746                                 LogExit( "Coupled duelists won." );
02747                                 gDuelExit = qfalse;
02748                         }
02749                         else if ((!g_entities[duelists[1]].inuse ||
02750                                 !g_entities[duelists[1]].client ||
02751                                 g_entities[duelists[1]].client->sess.sessionTeam != TEAM_FREE ||
02752                                 g_entities[duelists[1]].client->ps.stats[STAT_HEALTH] <= 0) &&
02753                                 (!g_entities[duelists[2]].inuse ||
02754                                 !g_entities[duelists[2]].client ||
02755                                 g_entities[duelists[2]].client->sess.sessionTeam != TEAM_FREE ||
02756                                 g_entities[duelists[2]].client->ps.stats[STAT_HEALTH] <= 0))
02757                         { //the coupled duelists lost, give the lone duelist a win (if applicable) and the couple both losses
02758                                 if (g_entities[duelists[1]].inuse &&
02759                                         g_entities[duelists[1]].client)
02760                                 {
02761                                         g_entities[duelists[1]].client->sess.losses++;
02762                                         ClientUserinfoChanged(duelists[1]);
02763                                 }
02764                                 if (g_entities[duelists[2]].inuse &&
02765                                         g_entities[duelists[2]].client)
02766                                 {
02767                                         g_entities[duelists[2]].client->sess.losses++;
02768                                         ClientUserinfoChanged(duelists[2]);
02769                                 }
02770 
02771                                 if (g_entities[duelists[0]].inuse &&
02772                                         g_entities[duelists[0]].client &&
02773                                         g_entities[duelists[0]].client->ps.stats[STAT_HEALTH] > 0 &&
02774                                         g_entities[duelists[0]].client->sess.sessionTeam == TEAM_FREE)
02775                                 {
02776                                         g_entities[duelists[0]].client->sess.wins++;
02777                                         ClientUserinfoChanged(duelists[0]);
02778                                 }
02779 
02780                                 trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", duelists[0] ) );
02781 
02782                                 if (d_powerDuelPrint.integer)
02783                                 {
02784                                         Com_Printf("POWERDUEL WIN CONDITION: Lone duelist won (1)\n");
02785                                 }
02786                                 LogExit( "Lone duelist won." );
02787                                 gDuelExit = qfalse;
02788                         }
02789                 }
02790                 */
02791                 return;
02792         }
02793 
02794         if ( level.numPlayingClients < 2 ) {
02795                 return;
02796         }
02797 
02798         if (g_gametype.integer == GT_DUEL ||
02799                 g_gametype.integer == GT_POWERDUEL)
02800         {
02801                 if (g_fraglimit.integer > 1)
02802                 {
02803                         sKillLimit = "Kill limit hit.";
02804                 }
02805                 else
02806                 {
02807                         sKillLimit = "";
02808                         printLimit = qfalse;
02809                 }
02810         }
02811         else
02812         {
02813                 sKillLimit = "Kill limit hit.";
02814         }
02815         if ( g_gametype.integer < GT_SIEGE && g_fraglimit.integer ) {
02816                 if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
02817                         trap_SendServerCommand( -1, va("print \"Red %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02818                         if (d_powerDuelPrint.integer)
02819                         {
02820                                 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (1)\n");
02821                         }
02822                         LogExit( sKillLimit );
02823                         return;
02824                 }
02825 
02826                 if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
02827                         trap_SendServerCommand( -1, va("print \"Blue %s\n\"", G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")) );
02828                         if (d_powerDuelPrint.integer)
02829                         {
02830                                 Com_Printf("POWERDUEL WIN CONDITION: Kill limit (2)\n");
02831                         }
02832                         LogExit( sKillLimit );
02833                         return;
02834                 }
02835 
02836                 for ( i=0 ; i< g_maxclients.integer ; i++ ) {
02837                         cl = level.clients + i;
02838                         if ( cl->pers.connected != CON_CONNECTED ) {
02839                                 continue;
02840                         }
02841                         if ( cl->sess.sessionTeam != TEAM_FREE ) {
02842                                 continue;
02843                         }
02844 
02845                         if ( (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) && g_duel_fraglimit.integer && cl->sess.wins >= g_duel_fraglimit.integer )
02846                         {
02847                                 if (d_powerDuelPrint.integer)
02848                                 {
02849                                         Com_Printf("POWERDUEL WIN CONDITION: Duel limit hit (1)\n");
02850                                 }
02851                                 LogExit( "Duel limit hit." );
02852                                 gDuelExit = qtrue;
02853                                 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the win limit.\n\"",
02854                                         cl->pers.netname ) );
02855                                 return;
02856                         }
02857 
02858                         if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
02859                                 if (d_powerDuelPrint.integer)
02860                                 {
02861                                         Com_Printf("POWERDUEL WIN CONDITION: Kill limit (3)\n");
02862                                 }
02863                                 LogExit( sKillLimit );
02864                                 gDuelExit = qfalse;
02865                                 if (printLimit)
02866                                 {
02867                                         trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s.\n\"",
02868                                                                                                         cl->pers.netname,
02869                                                                                                         G_GetStringEdString("MP_SVGAME", "HIT_THE_KILL_LIMIT")
02870                                                                                                         ) 
02871                                                                                         );
02872                                 }
02873                                 return;
02874                         }
02875                 }
02876         }
02877 
02878         if ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {
02879 
02880                 if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) 
02881                 {
02882                         trap_SendServerCommand( -1,  va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTREDTEAM")));
02883                         trap_SendServerCommand( -1,  va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02884                         LogExit( "Capturelimit hit." );
02885                         return;
02886                 }
02887 
02888                 if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
02889                         trap_SendServerCommand( -1,  va("print \"%s \"", G_GetStringEdString("MP_SVGAME", "PRINTBLUETEAM")));
02890                         trap_SendServerCommand( -1,  va("print \"%s.\n\"", G_GetStringEdString("MP_SVGAME", "HIT_CAPTURE_LIMIT")));
02891                         LogExit( "Capturelimit hit." );
02892                         return;
02893                 }
02894         }
02895 }

void DeathFX gentity_t ent  ) 
 

Definition at line 1882 of file g_combat.c.

References AngleVectors(), CHAN_AUTO, CLASS_ATST, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_R5D2, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, G_EffectIndex(), G_PlayEffectID(), G_Sound(), G_SoundIndex(), gentity_t, gclient_s::NPC_class, NULL, Q_irand(), gentity_s::r, va(), vec3_t, VectorCopy, VectorMA, and VectorSet.

Referenced by player_die().

01883 {
01884         vec3_t          effectPos, right;
01885         vec3_t          defaultDir;
01886 
01887         if ( !ent || !ent->client )
01888                 return;
01889 
01890         VectorSet(defaultDir, 0, 0, 1);
01891 
01892         // team no longer indicates species/race.  NPC_class should be used to identify certain npc types
01893         switch(ent->client->NPC_class)
01894         {
01895         case CLASS_MOUSE:
01896                 VectorCopy( ent->r.currentOrigin, effectPos );
01897                 effectPos[2] -= 20;
01898                 G_PlayEffectID( G_EffectIndex("env/small_explode"), effectPos, defaultDir );
01899                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mouse/misc/death1") );
01900                 break;
01901 
01902         case CLASS_PROBE:
01903                 VectorCopy( ent->r.currentOrigin, effectPos );
01904                 effectPos[2] += 50;
01905                 G_PlayEffectID( G_EffectIndex("explosions/probeexplosion1"), effectPos, defaultDir );
01906                 break;
01907                 
01908         case CLASS_ATST: 
01909                 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01910                 VectorMA( ent->r.currentOrigin, 20, right, effectPos );
01911                 effectPos[2] += 180;
01912                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01913                 VectorMA( effectPos, -40, right, effectPos );
01914                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01915                 break;
01916 
01917         case CLASS_SEEKER:
01918         case CLASS_REMOTE:
01919                 G_PlayEffectID( G_EffectIndex("env/small_explode"), ent->r.currentOrigin, defaultDir );
01920                 break;
01921 
01922         case CLASS_GONK:
01923                 VectorCopy( ent->r.currentOrigin, effectPos );
01924                 effectPos[2] -= 5;
01925 //              statusTextIndex = Q_irand( IGT_RESISTANCEISFUTILE, IGT_NAMEIS8OF12 );
01926                 G_Sound( ent, CHAN_AUTO, G_SoundIndex(va("sound/chars/gonk/misc/death%d.wav",Q_irand( 1, 3 ))) );
01927                 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01928                 break;
01929 
01930         // should list all remaining droids here, hope I didn't miss any
01931         case CLASS_R2D2:
01932                 VectorCopy( ent->r.currentOrigin, effectPos );
01933                 effectPos[2] -= 10;
01934                 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01935                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01936                 break;
01937 
01938         case CLASS_PROTOCOL: //c3p0
01939         case CLASS_R5D2:
01940                 VectorCopy( ent->r.currentOrigin, effectPos );
01941                 effectPos[2] -= 10;
01942                 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01943                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01944                 break;
01945 
01946         case CLASS_MARK2:
01947                 VectorCopy( ent->r.currentOrigin, effectPos );
01948                 effectPos[2] -= 15;
01949                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01950                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark2/misc/mark2_explo") );
01951                 break;
01952 
01953         case CLASS_INTERROGATOR:
01954                 VectorCopy( ent->r.currentOrigin, effectPos );
01955                 effectPos[2] -= 15;
01956                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01957                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/interrogator/misc/int_droid_explo") );
01958                 break;
01959 
01960         case CLASS_MARK1:
01961                 AngleVectors( ent->r.currentAngles, NULL, right, NULL );
01962                 VectorMA( ent->r.currentOrigin, 10, right, effectPos );
01963                 effectPos[2] -= 15;
01964                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01965                 VectorMA( effectPos, -20, right, effectPos );
01966                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01967                 VectorMA( effectPos, -20, right, effectPos );
01968                 G_PlayEffectID( G_EffectIndex("explosions/droidexplosion1"), effectPos, defaultDir );
01969                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/mark1/misc/mark1_explo") );
01970                 break;
01971 
01972         case CLASS_SENTRY:
01973                 G_Sound( ent, CHAN_AUTO, G_SoundIndex("sound/chars/sentry/misc/sentry_explo") );
01974                 VectorCopy( ent->r.currentOrigin, effectPos );
01975                 G_PlayEffectID( G_EffectIndex("env/med_explode"), effectPos, defaultDir );
01976                 break;
01977 
01978         default:
01979                 break;
01980 
01981         }
01982 
01983 }

void DismembermentByNum gentity_t self,
int  num
 

Definition at line 3510 of file g_combat.c.

References BOTH_DEATH1, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_Dismember(), G_GetDismemberBolt(), gentity_t, qfalse, and vec3_t.

Referenced by ClientCommand().

03511 {
03512         int sect = G2_MODELPART_HEAD;
03513         vec3_t boltPoint;
03514 
03515         switch (num)
03516         {
03517         case 0:
03518                 sect = G2_MODELPART_HEAD;
03519                 break;
03520         case 1:
03521                 sect = G2_MODELPART_WAIST;
03522                 break;
03523         case 2:
03524                 sect = G2_MODELPART_LARM;
03525                 break;
03526         case 3:
03527                 sect = G2_MODELPART_RARM;
03528                 break;
03529         case 4:
03530                 sect = G2_MODELPART_RHAND;
03531                 break;
03532         case 5:
03533                 sect = G2_MODELPART_LLEG;
03534                 break;
03535         case 6:
03536                 sect = G2_MODELPART_RLEG;
03537                 break;
03538         default:
03539                 break;
03540         }
03541 
03542         G_GetDismemberBolt(self, boltPoint, sect);
03543         G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03544 }

void DismembermentTest gentity_t self  ) 
 

Definition at line 3497 of file g_combat.c.

References BOTH_DEATH1, G2_MODELPART_HEAD, G2_MODELPART_RLEG, G_Dismember(), G_GetDismemberBolt(), gentity_t, qfalse, and vec3_t.

Referenced by ClientCommand().

03498 {
03499         int sect = G2_MODELPART_HEAD;
03500         vec3_t boltPoint;
03501 
03502         while (sect <= G2_MODELPART_RLEG)
03503         {
03504                 G_GetDismemberBolt(self, boltPoint, sect);
03505                 G_Dismember( self, self, boltPoint, sect, 90, 0, BOTH_DEATH1, qfalse );
03506                 sect++;
03507         }
03508 }

void ExplodeDeath gentity_t self  ) 
 

Definition at line 368 of file g_combat.c.

References entityState_s::angles, AngleVectors(), entityShared_t::currentOrigin, G_RadiusDamage(), gentity_t, entityState_s::loopIsSoundset, entityState_s::loopSound, MOD_UNKNOWN, NULL, ObjectDie(), gentity_s::parent, entityState_s::pos, qfalse, gentity_s::r, gentity_s::s, gentity_s::splashDamage, gentity_s::splashRadius, gentity_s::takedamage, trajectory_t::trBase, vec3_t, and VectorCopy.

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 }

void G_AddPowerDuelLoserScore int  team,
int  score
 

Definition at line 2036 of file g_combat.c.

References gentity_s::client, ClientUserinfoChanged(), CON_CONNECTED, clientPersistant_t::connected, clientSession_t::duelTeam, g_entities, gentity_t, gclient_s::iAmALoser, gentity_s::inuse, clientSession_t::losses, MAX_CLIENTS, entityState_s::number, gclient_s::pers, gclient_s::ps, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, STAT_HEALTH, playerState_s::stats, and TEAM_SPECTATOR.

Referenced by player_die().

02037 {
02038         int i = 0;
02039         gentity_t *check;
02040 
02041         while (i < MAX_CLIENTS)
02042         {
02043                 check = &g_entities[i];
02044                 if (check->inuse && check->client &&
02045                         check->client->pers.connected == CON_CONNECTED &&
02046                         (check->client->iAmALoser || (check->client->ps.stats[STAT_HEALTH] <= 0 && check->client->sess.sessionTeam != TEAM_SPECTATOR)) &&
02047                         check->client->sess.duelTeam == team)
02048                 { //found a living client on the specified team
02049                         check->client->sess.losses += score;
02050                         ClientUserinfoChanged(check->s.number);
02051                 }
02052                 i++;
02053         }
02054 }

void G_AddPowerDuelScore int  team,
int  score
 

Definition at line 2015 of file g_combat.c.

References gentity_s::client, ClientUserinfoChanged(), CON_CONNECTED, clientPersistant_t::connected, clientSession_t::duelTeam, g_entities, gentity_t, gclient_s::iAmALoser, gentity_s::inuse, MAX_CLIENTS, entityState_s::number, gclient_s::pers, gclient_s::ps, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, STAT_HEALTH, playerState_s::stats, TEAM_SPECTATOR, and clientSession_t::wins.

Referenced by player_die().

02016 {
02017         int i = 0;
02018         gentity_t *check;
02019 
02020         while (i < MAX_CLIENTS)
02021         {
02022                 check = &g_entities[i];
02023                 if (check->inuse && check->client &&
02024                         check->client->pers.connected == CON_CONNECTED && !check->client->iAmALoser &&
02025                         check->client->ps.stats[STAT_HEALTH] > 0 &&
02026                         check->client->sess.sessionTeam != TEAM_SPECTATOR &&
02027                         check->client->sess.duelTeam == team)
02028                 { //found a living client on the specified team
02029                         check->client->sess.wins += score;
02030                         ClientUserinfoChanged(check->s.number);
02031                 }
02032                 i++;
02033         }
02034 }

void G_AlertTeam gentity_t victim,
gentity_t attacker,
float  radius,
float  soundDist
 

Definition at line 1769 of file g_combat.c.

References gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, g_entities, G_SetEnemy(), gentity_t, gentity_s::health, gNPCstats_e::hfov, InFOV(), gentity_s::NPC, NPC_ClearLOS2(), NULL, gclient_s::playerTeam, gentity_s::r, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_NO_GROUPS, gNPC_t::scriptFlags, gNPC_t::stats, trap_EntitiesInBox(), trap_InPVS(), vec3_t, and gNPCstats_e::vfov.

Referenced by G_AngerAlert(), and G_DeathAlert().

01770 {
01771         int                     radiusEnts[ 128 ];
01772         gentity_t       *check;
01773         vec3_t          mins, maxs;
01774         int                     numEnts;
01775         int                     i;
01776         float           distSq, sndDistSq = (soundDist*soundDist);
01777 
01778         if ( attacker == NULL || attacker->client == NULL )
01779                 return;
01780 
01781         //Setup the bbox to search in
01782         for ( i = 0; i < 3; i++ )
01783         {
01784                 mins[i] = victim->r.currentOrigin[i] - radius;
01785                 maxs[i] = victim->r.currentOrigin[i] + radius;
01786         }
01787 
01788         //Get the number of entities in a given space
01789         numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 );
01790 
01791         //Cull this list
01792         for ( i = 0; i < numEnts; i++ )
01793         {
01794                 check = &g_entities[radiusEnts[i]];
01795 
01796                 //Validate clients
01797                 if ( check->client == NULL )
01798                         continue;
01799 
01800                 //only want NPCs
01801                 if ( check->NPC == NULL )
01802                         continue;
01803 
01804                 //Don't bother if they're ignoring enemies
01805 //              if ( check->svFlags & SVF_IGNORE_ENEMIES )
01806 //                      continue;
01807 
01808                 //This NPC specifically flagged to ignore alerts
01809                 if ( check->NPC->scriptFlags & SCF_IGNORE_ALERTS )
01810                         continue;
01811 
01812                 //This NPC specifically flagged to ignore alerts
01813                 if ( !(check->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES) )
01814                         continue;
01815 
01816                 //this ent does not participate in group AI
01817                 if ( (check->NPC->scriptFlags&SCF_NO_GROUPS) )
01818                         continue;
01819 
01820                 //Skip the requested avoid check if present
01821                 if ( check == victim )
01822                         continue;
01823 
01824                 //Skip the attacker
01825                 if ( check == attacker )
01826                         continue;
01827 
01828                 //Must be on the same team
01829                 if ( check->client->playerTeam != victim->client->playerTeam )
01830                         continue;
01831 
01832                 //Must be alive
01833                 if ( check->health <= 0 )
01834                         continue;
01835 
01836                 if ( check->enemy == NULL )
01837                 {//only do this if they're not already mad at someone
01838                         distSq = DistanceSquared( check->r.currentOrigin, victim->r.currentOrigin );
01839                         if ( distSq > 16384 /*128 squared*/ && !trap_InPVS( victim->r.currentOrigin, check->r.currentOrigin ) )
01840                         {//not even potentially visible/hearable
01841                                 continue;
01842                         }
01843                         //NOTE: this allows sound alerts to still go through doors/PVS if the teammate is within 128 of the victim...
01844                         if ( soundDist <= 0 || distSq > sndDistSq )
01845                         {//out of sound range
01846                                 if ( !InFOV( victim, check, check->NPC->stats.hfov, check->NPC->stats.vfov ) 
01847                                         ||  !NPC_ClearLOS2( check, victim->r.currentOrigin ) )
01848                                 {//out of FOV or no LOS
01849                                         continue;
01850                                 }
01851                         }
01852 
01853                         //FIXME: This can have a nasty cascading effect if setup wrong...
01854                         G_SetEnemy( check, attacker );
01855                 }
01856         }
01857 }

void G_ApplyKnockback gentity_t targ,
vec3_t  newDir,
float  knockback
 

Definition at line 2949 of file g_combat.c.

References gentity_s::client, entityShared_t::currentOrigin, g_gravity, g_knockback, gentity_t, level, gentity_s::physicsBounce, playerState_s::pm_flags, playerState_s::pm_time, PMF_TIME_KNOCKBACK, entityState_s::pos, gclient_s::ps, gentity_s::r, gentity_s::s, level_locals_t::time, TR_LINEAR_STOP, TR_NONLINEAR_STOP, TR_STATIONARY, trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, vmCvar_t::value, vec3_t, VectorAdd, VectorCopy, VectorScale, and playerState_s::velocity.

Referenced by DoImpact().

02950 {
02951         vec3_t  kvel;
02952         float   mass;
02953 
02954         if ( targ->physicsBounce > 0 )  //overide the mass
02955                 mass = targ->physicsBounce;
02956         else
02957                 mass = 200;
02958 
02959         if ( g_gravity.value > 0 )
02960         {
02961                 VectorScale( newDir, g_knockback.value * (float)knockback / mass * 0.8, kvel );
02962                 kvel[2] = newDir[2] * g_knockback.value * (float)knockback / mass * 1.5;
02963         }
02964         else
02965         {
02966                 VectorScale( newDir, g_knockback.value * (float)knockback / mass, kvel );
02967         }
02968 
02969         if ( targ->client )
02970         {
02971                 VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
02972         }
02973         else if ( targ->s.pos.trType != TR_STATIONARY && targ->s.pos.trType != TR_LINEAR_STOP && targ->s.pos.trType != TR_NONLINEAR_STOP )
02974         {
02975                 VectorAdd( targ->s.pos.trDelta, kvel, targ->s.pos.trDelta );
02976                 VectorCopy( targ->r.currentOrigin, targ->s.pos.trBase );
02977                 targ->s.pos.trTime = level.time;
02978         }
02979 
02980         // set the timer so that the other client can't cancel
02981         // out the movement immediately
02982         if ( targ->client && !targ->client->ps.pm_time ) 
02983         {
02984                 int             t;
02985 
02986                 t = knockback * 2;
02987                 if ( t < 50 ) {
02988                         t = 50;
02989                 }
02990                 if ( t > 200 ) {
02991                         t = 200;
02992                 }
02993                 targ->client->ps.pm_time = t;
02994                 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
02995         }
02996 }

void G_CheckForDismemberment gentity_t ent,
gentity_t enemy,
vec3_t  point,
int  damage,
int  deathAnim,
qboolean  postDeath
 

Definition at line 4093 of file g_combat.c.

References CLASS_PROTOCOL, gentity_s::client, d_saberGhoul2Collision, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, gclient_s::g2LastSurfaceHit, gclient_s::g2LastSurfaceTime, g_austrian, g_dismember, G_Dismember(), g_gametype, G_GetDismemberBolt(), G_GetDismemberLoc(), G_GetHitLocation(), G_GetHitLocFromSurfName(), G_GetHitQuad(), G_LogPrintf(), gentity_t, gGAvoidDismember, gentity_s::ghoul2, GT_DUEL, GT_POWERDUEL, hitLocName, HL_ARM_LT, HL_ARM_RT, HL_FOOT_LT, HL_FOOT_RT, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MAX_QPATH, MOD_UNKNOWN, clientPersistant_t::netname, gentity_s::NPC, gclient_s::NPC_class, gclient_s::pers, Q_irand(), level_locals_t::time, trap_G2API_GetSurfaceName(), vec3_origin, and vec3_t.

Referenced by ClientCommand(), ClientThink_real(), G_Damage(), and player_die().

04094 {
04095         int hitLoc = -1, hitLocUse = -1;
04096         vec3_t boltPoint;
04097         int dismember = g_dismember.integer;
04098 
04099         if (ent->localAnimIndex > 1)
04100         {
04101                 if (!ent->NPC)
04102                 {
04103                         return;
04104                 }
04105 
04106                 if (ent->client->NPC_class != CLASS_PROTOCOL)
04107                 { //this is the only non-humanoid allowed to do dismemberment.
04108                         return;
04109                 }
04110         }
04111 
04112         if (!dismember)
04113         {
04114                 return;
04115         }
04116 
04117         if (gGAvoidDismember == 1)
04118         {
04119                 return;
04120         }
04121 
04122         if (gGAvoidDismember != 2)
04123         { //this means do the dismemberment regardless of randomness and damage
04124                 if (Q_irand(0, 100) > dismember)
04125                 {
04126                         return;
04127                 }
04128 
04129                 if (damage < 5)
04130                 {
04131                         return;
04132                 }
04133         }
04134 
04135         if (gGAvoidDismember == 2)
04136         {
04137                 hitLoc = HL_HAND_RT;
04138         }
04139         else
04140         {
04141                 if (d_saberGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time)
04142                 {
04143                         char hitSurface[MAX_QPATH];
04144 
04145                         trap_G2API_GetSurfaceName(ent->ghoul2, ent->client->g2LastSurfaceHit, 0, hitSurface);
04146 
04147                         if (hitSurface[0])
04148                         {
04149                                 G_GetHitLocFromSurfName(ent, hitSurface, &hitLoc, point, vec3_origin, vec3_origin, MOD_UNKNOWN);
04150                         }
04151                 }
04152 
04153                 if (hitLoc == -1)
04154                 {
04155                         hitLoc = G_GetHitLocation( ent, point );
04156                 }
04157         }
04158 
04159         switch(hitLoc)
04160         {
04161         case HL_FOOT_RT:
04162         case HL_LEG_RT:
04163                 hitLocUse = G2_MODELPART_RLEG;
04164                 break;
04165         case HL_FOOT_LT:
04166         case HL_LEG_LT:
04167                 hitLocUse = G2_MODELPART_LLEG;
04168                 break;
04169                 
04170         case HL_WAIST:
04171                 hitLocUse = G2_MODELPART_WAIST;
04172                 break;
04173                 /*
04174         case HL_BACK_RT:
04175         case HL_BACK_LT:
04176         case HL_BACK:
04177         case HL_CHEST_RT:
04178         case HL_CHEST_LT:
04179         case HL_CHEST:
04180                 break;
04181                 */
04182         case HL_ARM_RT:
04183                 hitLocUse = G2_MODELPART_RARM;
04184                 break;
04185         case HL_HAND_RT:
04186                 hitLocUse = G2_MODELPART_RHAND;
04187                 break;
04188         case HL_ARM_LT:
04189         case HL_HAND_LT:
04190                 hitLocUse = G2_MODELPART_LARM;
04191                 break;
04192         case HL_HEAD:
04193                 hitLocUse = G2_MODELPART_HEAD;
04194                 break;
04195         default:
04196                 hitLocUse = G_GetHitQuad(ent, point);
04197                 break;
04198         }
04199 
04200         if (hitLocUse == -1)
04201         {
04202                 return;
04203         }
04204 
04205         if (ent->client)
04206         {
04207                 G_GetDismemberBolt(ent, boltPoint, hitLocUse);
04208                 if ( g_austrian.integer 
04209                         && (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) )
04210                 {
04211                         G_LogPrintf( "Duel Dismemberment: %s dismembered at %s\n", ent->client->pers.netname, hitLocName[hitLoc] );
04212                 }
04213         }
04214         else
04215         {
04216                 G_GetDismemberLoc(ent, boltPoint, hitLocUse);
04217         }
04218         G_Dismember(ent, enemy, boltPoint, hitLocUse, 90, 0, deathAnim, postDeath);
04219 }

void G_CheckVictoryScript gentity_t self  ) 
 

Definition at line 1985 of file g_combat.c.

References gNPC_t::blockedSpeechDebounceTime, BSET_VICTORY, CLASS_GALAKMECH, gentity_s::client, AIGroupInfo_s::commander, G_ActivateBehavior(), gentity_t, gNPC_t::greetingDebounceTime, gNPC_t::group, level, gentity_s::NPC, gclient_s::NPC_class, Q_irand(), gNPC_t::rank, gentity_s::s, level_locals_t::time, TIMER_Set(), gentity_s::wait, entityState_s::weapon, and WP_SABER.

Referenced by player_die().

01986 {
01987         if ( !G_ActivateBehavior( self, BSET_VICTORY ) )
01988         {
01989                 if ( self->NPC && self->s.weapon == WP_SABER )
01990                 {//Jedi taunt from within their AI
01991                         self->NPC->blockedSpeechDebounceTime = 0;//get them ready to taunt
01992                         return;
01993                 }
01994                 if ( self->client && self->client->NPC_class == CLASS_GALAKMECH )
01995                 {
01996                         self->wait = 1;
01997                         TIMER_Set( self, "gloatTime", Q_irand( 5000, 8000 ) );
01998                         self->NPC->blockedSpeechDebounceTime = 0;//get him ready to taunt
01999                         return;
02000                 }
02001                 //FIXME: any way to not say this *right away*?  Wait for victim's death anim/scream to finish?
02002                 if ( self->NPC && self->NPC->group && self->NPC->group->commander && self->NPC->group->commander->NPC && self->NPC->group->commander->NPC->rank > self->NPC->rank && !Q_irand( 0, 2 ) )
02003                 {//sometimes have the group commander speak instead
02004                         self->NPC->group->commander->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02005                         //G_AddVoiceEvent( self->NPC->group->commander, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 );
02006                 }
02007                 else if ( self->NPC )
02008                 {
02009                         self->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 );
02010                         //G_AddVoiceEvent( self, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 );
02011                 }
02012         }
02013 }

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 4369 of file g_combat.c.

References gentity_s::activator, gentity_s::alliedTeam, AngleVectors(), bgSiegeClasses, BotDamageNotification(), BROKENLIMB_LARM, BROKENLIMB_RARM, playerState_s::brokenLimbs, BSET_DEATH, CFL_STRONGAGAINSTPHYSICAL, CheckArmor(), CLASS_ATST, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_R5D2, CLASS_RANCOR, CLASS_SEEKER, CLASS_SENTRY, CLASS_VEHICLE, client, gentity_s::client, playerState_s::clientNum, entityShared_t::currentOrigin, gclient_s::damage_armor, gclient_s::damage_blood, gclient_s::damage_from, gclient_s::damage_fromWorld, gclient_s::damage_knockback, DAMAGE_NO_DISMEMBER, DAMAGE_NO_HIT_LOC, DAMAGE_NO_KNOCKBACK, DAMAGE_NO_PROTECTION, DAMAGE_NO_SELF_PROTECTION, DAMAGE_RADIUS, DAMAGE_SABER_KNOCKBACK1, DAMAGE_SABER_KNOCKBACK1_B2, DAMAGE_SABER_KNOCKBACK2, DAMAGE_SABER_KNOCKBACK2_B2, gentity_s::damageRedirect, gentity_s::damageRedirectTo, gentity_s::die, DirToByte(), DotProduct, playerState_s::duelIndex, playerState_s::duelInProgress, EF_DEAD, EF_INVULNERABLE, playerState_s::eFlags, entityState_s::eFlags, playerState_s::electrifyTime, gentity_s::enemy, ENTITYNUM_WORLD, ET_GENERAL, ET_MISSILE, ET_MOVER, ET_NPC, ET_PLAYER, entityState_s::eType, EV_POWERUP_BATTLESUIT, EV_SHIELD_HIT, entityState_s::eventParm, playerState_s::fd, FL_BBRUSH, FL_DMG_BY_HEAVY_WEAP_ONLY, FL_DMG_BY_SABER_ONLY, FL_GODMODE, FL_NO_KNOCKBACK, FL_SHIELDED, FL_UNDYING, gentity_s::flags, FORCE_LEVEL_1, FORCE_LEVEL_2, FORCE_LEVEL_3, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcedata_s::forcePowersActive, gclient_s::forcePowerSoundDebounce, FP_PROTECT, FP_RAGE, trace_t::fraction, gclient_s::g2LastSurfaceHit, gclient_s::g2LastSurfaceTime, G_ActivateBehavior(), G_AddEvent(), g_armBreakage, G_BreakArm(), G_CheckForDismemberment(), g_debugDamage, g_debugMelee, g_entities, g_ff_objectives, G_FlyVehicleDestroySurface(), g_friendlyFire, g_gametype, G_GetHitLocFromSurfName(), G_HeavyMelee(), g_knockback, G_LetGoOfWall(), G_LocationBasedDamageModifier(), G_LogWeaponDamage(), G_PreDefSound(), G_Printf(), g_saberDmgVelocityScale, G_ScaleNetHealth(), G_ShipSurfaceForSurfName(), G_TempEntity(), G_ThereIsAMaster(), g_trueJedi, G_VehicleSetDamageLocFlags(), G_VehUpdateShields(), gclient_t, gentity_s::genericValue4, gentity_t, gentity_s::ghoul2, GlobalUse(), gPainHitLoc, gPainMOD, gPainPoint, gSiegeRoundBegun, GT_CTF, GT_CTY, GT_JEDIMASTER, GT_SIEGE, GT_TEAM, gentity_s::health, vehicleInfo_t::health_back, vehicleInfo_t::health_front, vehicleInfo_t::health_left, vehicleInfo_t::health_right, HL_ARM_LT, HL_ARM_RT, HL_HAND_LT, HL_HAND_RT, vmCvar_t::integer, level_locals_t::intermissionQueued, gentity_s::inuse, gclient_s::invulnerableTimer, playerState_s::isJediMaster, Jetpack_Off(), gclient_s::jetPackOn, gclient_s::jetPackToggleTime, saberInfo_t::knockbackScale, saberInfo_t::knockbackScale2, gclient_s::lasthurt_client, gclient_s::lasthurt_mod, level, gentity_s::locationDamage, Vehicle_s::m_iArmor, Vehicle_s::m_iShields, playerState_s::m_iVehicleNum, Vehicle_s::m_LandTrace, gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, Vehicle_s::m_vOrientation, MAX_CLIENTS, MAX_QPATH, gentity_s::maxHealth, MOD_BRYAR_PISTOL, MOD_BRYAR_PISTOL_ALT, MOD_CONC, MOD_CONC_ALT, MOD_CRUSH, MOD_DEMP2, MOD_DEMP2_ALT, MOD_DET_PACK_SPLASH, MOD_FALLING, MOD_FLECHETTE_ALT_SPLASH, MOD_MELEE, MOD_REPEATER_ALT, MOD_REPEATER_ALT_SPLASH, MOD_ROCKET, MOD_ROCKET_HOMING, MOD_ROCKET_HOMING_SPLASH, MOD_ROCKET_SPLASH, MOD_SABER, MOD_SUICIDE, MOD_TELEFRAG, MOD_THERMAL, MOD_THERMAL_SPLASH, MOD_TIMED_MINE_SPLASH, MOD_TRIGGER_HURT, MOD_TRIP_MINE_SPLASH, MOD_TURBLAST, MOD_VEHICLE, MOVER_POS1, gentity_s::moverState, gclient_s::noclip, entityState_s::NPC_class, gclient_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), playerState_s::origin, entityState_s::otherEntityNum, playerState_s::otherKiller, playerState_s::otherKillerDebounceTime, playerState_s::otherKillerTime, entityState_s::owner, gentity_s::pain, PDSOUND_PROTECTHIT, PERS_ATTACKEE_ARMOR, PERS_ATTACKER, PERS_HITS, playerState_s::persistant, PITCH, playerState_s::pm_flags, playerState_s::pm_time, PMF_STUCK_TO_WALL, PMF_TIME_KNOCKBACK, gentity_s::pos1, gentity_s::pos2, playerState_s::powerups, gclient_s::ps, PW_BATTLESUIT, PW_FORCE_BOON, Q3_INFINITE, Q_irand(), qfalse, qtrue, gentity_s::r, ROLL, gentity_s::s, gclient_s::saber, gclient_s::sess, clientSession_t::sessionTeam, SHIPSURF_BACK, SHIPSURF_FRONT, SHIPSURF_LEFT, SHIPSURF_RIGHT, entityState_s::shouldtarget, gclient_s::siegeClass, STAT_ARMOR, STAT_HEALTH, STAT_MAX_HEALTH, playerState_s::stats, SVF_GLASS_BRUSH, entityShared_t::svFlags, gentity_s::takedamage, Team_CheckHurtCarrier(), gentity_s::teamnodmg, entityState_s::teamowner, level_locals_t::time, entityState_s::time2, playerState_s::torsoAnim, trap_G2API_GetSurfaceName(), playerState_s::trueJedi, playerState_s::trueNonJedi, vehicleInfo_t::type, gentity_s::use, vmCvar_t::value, vec3_origin, vec3_t, VectorAdd, VectorClear, VectorCopy, VectorNormalize(), VectorScale, VectorSubtract, playerState_s::velocity, VH_ANIMAL, VH_FIGHTER, VH_SPEEDER, VH_WALKER, playerState_s::weapon, WEAPON_CHARGING, WEAPON_CHARGING_ALT, WEAPON_READY, playerState_s::weaponstate, playerState_s::weaponTime, and WP_SABER.

Referenced by AnimateRiders(), Blocked_Door(), Blocked_Mover(), Boba_FireFlameThrower(), ClientEvents(), ClientThink_real(), Cmd_DuelTeam_f(), DEMP2_AltRadiusDamage(), DetPackBlow(), Do_Strike(), DoGripAction(), DoImpact(), EjectAll(), ForceLightningDamage(), funcBBrushDieGo(), G_EjectDroidUnit(), G_KillBox(), G_MissileImpact(), G_MoverPush(), G_RadiusDamage(), G_RunFrame(), G_RunStuckMissile(), G_TryPushingEntity(), Howler_TryDamage(), hurt_touch(), hyperspace_touch(), ImperialProbe_Wait(), Interrogator_Melee(), MineMonster_TryDamage(), NPC_BSGM_Attack(), NPC_BSSeeker_Default(), NPC_Mark1_Pain(), NPC_Mark2_Pain(), NPC_Seeker_Pain(), P_WorldEffects(), player_die(), PM_VehicleImpact(), Rancor_Attack(), Rancor_Bite(), Rancor_Crush(), Rancor_Smash(), Rancor_Swing(), Seeker_Ranged(), shipboundary_touch(), target_kill_use(), target_laser_think(), Wampa_Slash(), WP_DisruptorAltFire(), WP_FireMelee(), WP_FireStunBaton(), WP_SaberApplyDamage(), WP_SaberPositionUpdate(), and WP_SaberRadiusDamage().

04370                                                                                        {
04371         gclient_t       *client;
04372         int                     take;
04373         int                     save;
04374         int                     asave;
04375         int                     knockback;
04376         int                     max;
04377         int                     subamt = 0;
04378         float           famt = 0;
04379         float           hamt = 0;
04380         float           shieldAbsorbed = 0;
04381 
04382         if (targ && targ->damageRedirect)
04383         {
04384                 G_Damage(&g_entities[targ->damageRedirectTo], inflictor, attacker, dir, point, damage, dflags, mod);
04385                 return;
04386         }
04387 
04388         if (mod == MOD_DEMP2 && targ && targ->inuse && targ->client)
04389         {
04390                 if ( targ->client->ps.electrifyTime < level.time )
04391                 {//electrocution effect
04392                         if (targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE &&
04393                                 targ->m_pVehicle && (targ->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER || targ->m_pVehicle->m_pVehicleInfo->type == VH_WALKER))
04394                         { //do some extra stuff to speeders/walkers
04395                                 targ->client->ps.electrifyTime = level.time + Q_irand( 3000, 4000 );
04396                         }
04397                         else if ( targ->s.NPC_class != CLASS_VEHICLE 
04398                                 || (targ->m_pVehicle && targ->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER) )
04399                         {//don't do this to fighters
04400                                 targ->client->ps.electrifyTime = level.time + Q_irand( 300, 800 );
04401                         }
04402                 }
04403         }
04404 
04405         if (g_gametype.integer == GT_SIEGE &&
04406                 !gSiegeRoundBegun)
04407         { //nothing can be damaged til the round starts.
04408                 return;
04409         }
04410 
04411         if (!targ->takedamage) {
04412                 return;
04413         }
04414 
04415         if ( (targ->flags&FL_SHIELDED) && mod != MOD_SABER  && !targ->client)
04416         {//magnetically protected, this thing can only be damaged by lightsabers
04417                 return;
04418         }
04419 
04420         if ((targ->flags & FL_DMG_BY_SABER_ONLY) && mod != MOD_SABER)
04421         { //saber-only damage
04422                 return;
04423         }
04424 
04425         if ( targ->client )
04426         {//don't take damage when in a walker, or fighter
04427                 //unless the walker/fighter is dead!!! -rww
04428                 if ( targ->client->ps.clientNum < MAX_CLIENTS && targ->client->ps.m_iVehicleNum )
04429                 {
04430                         gentity_t *veh = &g_entities[targ->client->ps.m_iVehicleNum];
04431                         if ( veh->m_pVehicle && veh->health > 0 )
04432                         {
04433                                 if ( veh->m_pVehicle->m_pVehicleInfo->type == VH_WALKER ||
04434                                          veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER)
04435                                 {
04436                                         if (!(dflags & DAMAGE_NO_PROTECTION))
04437                                         {
04438                                                 return;
04439                                         }
04440                                 }
04441                         }
04442                 }
04443         }
04444 
04445         if ((targ->flags & FL_DMG_BY_HEAVY_WEAP_ONLY))
04446         { //only take damage from explosives and such
04447                 if (mod != MOD_REPEATER_ALT &&
04448                         mod != MOD_ROCKET &&
04449                         mod != MOD_FLECHETTE_ALT_SPLASH &&
04450                         mod != MOD_ROCKET_HOMING &&
04451                         mod != MOD_THERMAL &&
04452                         mod != MOD_THERMAL_SPLASH &&
04453                         mod != MOD_TRIP_MINE_SPLASH &&
04454                         mod != MOD_TIMED_MINE_SPLASH &&
04455                         mod != MOD_DET_PACK_SPLASH &&
04456                         mod != MOD_VEHICLE &&
04457                         mod != MOD_CONC &&
04458                         mod != MOD_CONC_ALT &&
04459                         mod != MOD_SABER &&
04460                         mod != MOD_TURBLAST &&
04461                         mod != MOD_SUICIDE &&
04462                         mod != MOD_FALLING &&
04463                         mod != MOD_CRUSH &&
04464                         mod != MOD_TELEFRAG &&
04465                         mod != MOD_TRIGGER_HURT)
04466                 {
04467                         if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04468                         { //let classes with heavy melee ability damage heavy wpn dmg doors with fists
04469                                 return;
04470                         }
04471                 }
04472         }
04473 
04474         if (targ->flags & FL_BBRUSH)
04475         {
04476                 if (mod == MOD_DEMP2 ||
04477                         mod == MOD_DEMP2_ALT ||
04478                         mod == MOD_BRYAR_PISTOL ||
04479                         mod == MOD_BRYAR_PISTOL_ALT ||
04480                         mod == MOD_MELEE)
04481                 { //these don't damage bbrushes.. ever
04482                         if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) )
04483                         { //let classes with heavy melee ability damage breakable brushes with fists
04484                                 return;
04485                         }
04486                 }
04487         }
04488 
04489         if (targ && targ->client && targ->client->ps.duelInProgress)
04490         {
04491                 if (attacker && attacker->client && attacker->s.number != targ->client->ps.duelIndex)
04492                 {
04493                         return;
04494                 }
04495                 else if (attacker && attacker->client && mod != MOD_SABER)
04496                 {
04497                         return;
04498                 }
04499         }
04500         if (attacker && attacker->client && attacker->client->ps.duelInProgress)
04501         {
04502                 if (targ && targ->client && targ->s.number != attacker->client->ps.duelIndex)
04503                 {
04504                         return;
04505                 }
04506                 else if (targ && targ->client && mod != MOD_SABER)
04507                 {
04508                         return;
04509                 }
04510         }
04511 
04512         if ( !(dflags & DAMAGE_NO_PROTECTION) ) 
04513         {//rage overridden by no_protection
04514                 if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)))
04515                 {
04516                         damage *= 0.5;
04517                 }
04518         }
04519 
04520         // the intermission has allready been qualified for, so don't
04521         // allow any extra scoring
04522         if ( level.intermissionQueued ) {
04523                 return;
04524         }
04525         if ( !inflictor ) {
04526                 inflictor = &g_entities[ENTITYNUM_WORLD];
04527         }
04528         if ( !attacker ) {
04529                 attacker = &g_entities[ENTITYNUM_WORLD];
04530         }
04531 
04532         // shootable doors / buttons don't actually have any health
04533 
04534         //if genericValue4 == 1 then it's glass or a breakable and those do have health
04535         if ( targ->s.eType == ET_MOVER && targ->genericValue4 != 1 ) {
04536                 if ( targ->use && targ->moverState == MOVER_POS1 ) {
04537                         GlobalUse( targ, inflictor, attacker );
04538                 }
04539                 return;
04540         }
04541         // reduce damage by the attacker's handicap value
04542         // unless they are rocket jumping
04543         if ( attacker->client 
04544                 && attacker != targ 
04545                 && attacker->s.eType == ET_PLAYER 
04546                 && g_gametype.integer != GT_SIEGE ) 
04547         {
04548                 max = attacker->client->ps.stats[STAT_MAX_HEALTH];
04549                 damage = damage * max / 100;
04550         }
04551 
04552         if ( !(dflags&DAMAGE_NO_HIT_LOC) )
04553         {//see if we should modify it by damage location
04554                 if (targ->inuse && (targ->client || targ->s.eType == ET_NPC) &&
04555                         attacker->inuse && (attacker->client || attacker->s.eType == ET_NPC))
04556                 { //check for location based damage stuff.
04557                         G_LocationBasedDamageModifier(targ, point, mod, dflags, &damage);
04558                 }
04559         }
04560 
04561         if ( targ->client 
04562                 && targ->client->NPC_class == CLASS_RANCOR 
04563                 && (!attacker||!attacker->client||attacker->client->NPC_class!=CLASS_RANCOR) )
04564         {
04565                 // I guess always do 10 points of damage...feel free to tweak as needed
04566                 if ( damage < 10 )
04567                 {//ignore piddly little damage
04568                         damage = 0;
04569                 }
04570                 else if ( damage >= 10 )
04571                 {
04572                         damage = 10;
04573                 }
04574         }
04575 
04576         client = targ->client;
04577 
04578         if ( client ) {
04579                 if ( client->noclip ) {
04580                         return;
04581                 }
04582         }
04583 
04584         if ( !dir ) {
04585                 dflags |= DAMAGE_NO_KNOCKBACK;
04586         } else {
04587                 VectorNormalize(dir);
04588         }
04589 
04590         knockback = damage;
04591         if ( knockback > 200 ) {
04592                 knockback = 200;
04593         }
04594         if ( targ->flags & FL_NO_KNOCKBACK ) {
04595                 knockback = 0;
04596         }
04597         if ( dflags & DAMAGE_NO_KNOCKBACK ) {
04598                 knockback = 0;
04599         }
04600 
04601         // figure momentum add, even if the damage won't be taken
04602         if ( knockback && targ->client ) {
04603                 vec3_t  kvel;
04604                 float   mass;
04605 
04606                 mass = 200;
04607 
04608                 if (mod == MOD_SABER)
04609                 {
04610                         float saberKnockbackScale = g_saberDmgVelocityScale.value;
04611                         if ( (dflags&DAMAGE_SABER_KNOCKBACK1)
04612                                 || (dflags&DAMAGE_SABER_KNOCKBACK2) )
04613                         {//saber does knockback, scale it by the right number
04614                                 if ( !saberKnockbackScale )
04615                                 {
04616                                         saberKnockbackScale = 1.0f;
04617                                 }
04618                                 if ( attacker
04619                                         && attacker->client )
04620                                 {
04621                                         if ( (dflags&DAMAGE_SABER_KNOCKBACK1) )
04622                                         {
04623                                                 if ( attacker && attacker->client )
04624                                                 {
04625                                                         saberKnockbackScale *= attacker->client->saber[0].knockbackScale;
04626                                                 }
04627                                         }
04628                                         if ( (dflags&DAMAGE_SABER_KNOCKBACK1_B2) )
04629                                         {
04630                                                 if ( attacker && attacker->client )
04631                                                 {
04632                                                         saberKnockbackScale *= attacker->client->saber[0].knockbackScale2;
04633                                                 }
04634                                         }
04635                                         if ( (dflags&DAMAGE_SABER_KNOCKBACK2) )
04636                                         {
04637                                                 if ( attacker && attacker->client )
04638                                                 {
04639                                                         saberKnockbackScale *= attacker->client->saber[1].knockbackScale;
04640                                                 }
04641                                         }
04642                                         if ( (dflags&DAMAGE_SABER_KNOCKBACK2_B2) )
04643                                         {
04644                                                 if ( attacker && attacker->client )
04645                                                 {
04646                                                         saberKnockbackScale *= attacker->client->saber[1].knockbackScale2;
04647                                                 }
04648                                         }
04649                                 }
04650                         }
04651                         VectorScale (dir, (g_knockback.value * (float)knockback / mass)*saberKnockbackScale, kvel);
04652                 }
04653                 else
04654                 {
04655                         VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
04656                 }
04657                 VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
04658 
04659                 if (attacker && attacker->client && attacker != targ)
04660                 {
04661                         float dur = 5000;
04662                         float dur2 = 100;
04663                         if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE)
04664                         {
04665                                 dur = 25000;
04666                                 dur2 = 25000;
04667                         }
04668                         targ->client->ps.otherKiller = attacker->s.number;
04669                         targ->client->ps.otherKillerTime = level.time + dur;
04670                         targ->client->ps.otherKillerDebounceTime = level.time + dur2;
04671                 }
04672                 // set the timer so that the other client can't cancel
04673                 // out the movement immediately
04674                 if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER || (dflags&DAMAGE_SABER_KNOCKBACK1) || (dflags&DAMAGE_SABER_KNOCKBACK2) || (dflags&DAMAGE_SABER_KNOCKBACK1_B2) || (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) ) {
04675                         int             t;
04676 
04677                         t = knockback * 2;
04678                         if ( t < 50 ) {
04679                                 t = 50;
04680                         }
04681                         if ( t > 200 ) {
04682                                 t = 200;
04683                         }
04684                         targ->client->ps.pm_time = t;
04685                         targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
04686                 }
04687         }
04688         else if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE && attacker != targ)
04689         {
04690                 targ->client->ps.otherKiller = attacker->s.number;
04691                 targ->client->ps.otherKillerTime = level.time + 25000;
04692                 targ->client->ps.otherKillerDebounceTime = level.time + 25000;
04693         }
04694 
04695         
04696         if ( (g_trueJedi.integer || g_gametype.integer == GT_SIEGE)
04697                 && client )
04698         {//less explosive damage for jedi, more saber damage for non-jedi
04699                 if ( client->ps.trueJedi 
04700                         || (g_gametype.integer == GT_SIEGE&&client->ps.weapon == WP_SABER))
04701                 {//if the target is a trueJedi, reduce splash and explosive damage to 1/2
04702                         switch ( mod )
04703                         {
04704                         case MOD_REPEATER_ALT:
04705                         case MOD_REPEATER_ALT_SPLASH:
04706                         case MOD_DEMP2_ALT:
04707                         case MOD_FLECHETTE_ALT_SPLASH:
04708                         case MOD_ROCKET:
04709                         case MOD_ROCKET_SPLASH:
04710                         case MOD_ROCKET_HOMING:
04711                         case MOD_ROCKET_HOMING_SPLASH:
04712                         case MOD_THERMAL:
04713                         case MOD_THERMAL_SPLASH:
04714                         case MOD_TRIP_MINE_SPLASH:
04715                         case MOD_TIMED_MINE_SPLASH:
04716                         case MOD_DET_PACK_SPLASH:
04717                                 damage *= 0.75;
04718                                 break;
04719                         }
04720                 }
04721                 else if ( (client->ps.trueNonJedi || (g_gametype.integer == GT_SIEGE&&client->ps.weapon != WP_SABER))
04722                         && mod == MOD_SABER )
04723                 {//if the target is a trueNonJedi, take more saber damage... combined with the 1.5 in the w_saber stuff, this is 6 times damage!
04724                         if ( damage < 100 )
04725                         {
04726                                 damage *= 4;
04727                                 if ( damage > 100 )
04728                                 {
04729                                         damage = 100;
04730                                 }
04731                         }
04732                 }
04733         }
04734 
04735         if (attacker->client && targ->client && g_gametype.integer == GT_SIEGE &&
04736                 targ->client->siegeClass != -1 && (bgSiegeClasses[targ->client->siegeClass].classflags & (1<<CFL_STRONGAGAINSTPHYSICAL)))
04737         { //this class is flagged to take less damage from physical attacks.
04738                 //For now I'm just decreasing against any client-based attack, this can be changed later I guess.
04739                 damage *= 0.5;
04740         }
04741 
04742         // check for completely getting out of the damage
04743         if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
04744 
04745                 // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
04746                 // if the attacker was on the same team
04747                 if ( targ != attacker)
04748                 {
04749                         if (OnSameTeam (targ, attacker))
04750                         {
04751                                 if ( !g_friendlyFire.integer )
04752                                 {
04753                                         return;
04754                                 }
04755                         }
04756                         else if (attacker && attacker->inuse &&
04757                                 !attacker->client && attacker->activator &&
04758                                 targ != attacker->activator &&
04759                                 attacker->activator->inuse && attacker->activator->client)
04760                         { //emplaced guns don't hurt teammates of user
04761                                 if (OnSameTeam (targ, attacker->activator))
04762                                 {
04763                                         if ( !g_friendlyFire.integer )
04764                                         {
04765                                                 return;
04766                                         }
04767                                 }
04768                         }
04769                         else if (targ->inuse && targ->client &&
04770                                 g_gametype.integer >= GT_TEAM &&
04771                                 attacker->s.number >= MAX_CLIENTS &&
04772                                 attacker->alliedTeam &&
04773                                 targ->client->sess.sessionTeam == attacker->alliedTeam &&
04774                                 !g_friendlyFire.integer)
04775                         { //things allied with my team should't hurt me.. I guess
04776                                 return;
04777                         }
04778                 }
04779 
04780                 if (g_gametype.integer == GT_JEDIMASTER && !g_friendlyFire.integer &&
04781                         targ && targ->client && attacker && attacker->client &&
04782                         targ != attacker && !targ->client->ps.isJediMaster && !attacker->client->ps.isJediMaster &&
04783                         G_ThereIsAMaster())
04784                 {
04785                         return;
04786                 }
04787 
04788                 if (targ->s.number >= MAX_CLIENTS && targ->client 
04789                         && targ->s.shouldtarget && targ->s.teamowner &&
04790                         attacker && attacker->inuse && attacker->client && targ->s.owner >= 0 && targ->s.owner < MAX_CLIENTS)
04791                 {
04792                         gentity_t *targown = &g_entities[targ->s.owner];
04793 
04794                         if (targown && targown->inuse && targown->client && OnSameTeam(targown, attacker))
04795                         {
04796                                 if (!g_friendlyFire.integer)
04797                                 {
04798                                         return;
04799                                 }
04800                         }
04801                 }
04802 
04803                 // check for godmode
04804                 if ( (targ->flags & FL_GODMODE) && targ->s.eType != ET_NPC ) {
04805                         return;
04806                 }
04807 
04808                 if (targ && targ->client && (targ->client->ps.eFlags & EF_INVULNERABLE) &&
04809                         attacker && attacker->client && targ != attacker)
04810                 {
04811                         if (targ->client->invulnerableTimer <= level.time)
04812                         {
04813                                 targ->client->ps.eFlags &= ~EF_INVULNERABLE;
04814                         }
04815                         else
04816                         {
04817                                 return;
04818                         }
04819                 }
04820         }
04821 
04822         //check for teamnodmg
04823         //NOTE: non-client objects hitting clients (and clients hitting clients) purposely doesn't obey this teamnodmg (for emplaced guns)
04824         if ( attacker && !targ->client )
04825         {//attacker hit a non-client
04826                 if ( g_gametype.integer == GT_SIEGE &&
04827                         !g_ff_objectives.integer )
04828                 {//in siege mode (and...?)
04829                         if ( targ->teamnodmg )
04830                         {//targ shouldn't take damage from a certain team
04831                                 if ( attacker->client )
04832                                 {//a client hit a non-client object
04833                                         if ( targ->teamnodmg == attacker->client->sess.sessionTeam )
04834                                         {
04835                                                 return;
04836                                         }
04837                                 }
04838                                 else if ( attacker->teamnodmg )
04839                                 {//a non-client hit a non-client object
04840                                         //FIXME: maybe check alliedTeam instead?
04841                                         if ( targ->teamnodmg == attacker->teamnodmg )
04842                                         {
04843                                                 if (attacker->activator &&
04844                                                         attacker->activator->inuse &&
04845                                                         attacker->activator->s.number < MAX_CLIENTS &&
04846                                                         attacker->activator->client &&
04847                                                         attacker->activator->client->sess.sessionTeam != targ->teamnodmg)
04848                                                 { //uh, let them damage it I guess.
04849                                                 }
04850                                                 else
04851                                                 {
04852                                                         return;
04853                                                 }
04854                                         }
04855                                 }
04856                         }
04857                 }
04858         }
04859 
04860         // battlesuit protects from all radius damage (but takes knockback)
04861         // and protects 50% against all damage
04862         if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
04863                 G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
04864                 if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
04865                         return;
04866                 }
04867                 damage *= 0.5;
04868         }
04869 
04870         // add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
04871         if ( attacker->client && targ != attacker && targ->health > 0
04872                         && targ->s.eType != ET_MISSILE
04873                         && targ->s.eType != ET_GENERAL
04874                         && client) {
04875                 if ( OnSameTeam( targ, attacker ) ) {
04876                         attacker->client->ps.persistant[PERS_HITS]--;
04877                 } else {
04878                         attacker->client->ps.persistant[PERS_HITS]++;
04879                 }
04880                 attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
04881         }
04882 
04883         // always give half damage if hurting self... but not in siege.  Heavy weapons need a counter.
04884         // calculated after knockback, so rocket jumping works
04885         if ( targ == attacker && !(dflags & DAMAGE_NO_SELF_PROTECTION)) {
04886                 if ( g_gametype.integer == GT_SIEGE )
04887                 {
04888                         damage *= 1.5;
04889                 }
04890                 else
04891                 {
04892                         damage *= 0.5;
04893                 }
04894         }
04895 
04896         if ( damage < 1 ) {
04897                 damage = 1;
04898         }
04899         take = damage;
04900         save = 0;
04901 
04902         // save some from armor
04903         asave = CheckArmor (targ, take, dflags);
04904 
04905         if (asave)
04906         {
04907                 shieldAbsorbed = asave;
04908         }
04909 
04910         take -= asave;
04911         if ( targ->client )
04912         {//update vehicle shields and armor, check for explode 
04913                 if ( targ->client->NPC_class == CLASS_VEHICLE &&
04914                         targ->m_pVehicle )
04915                 {//FIXME: should be in its own function in g_vehicles.c now, too big to be here
04916                         int surface = -1;
04917                         if ( attacker )
04918                         {//so we know the last guy who shot at us
04919                                 targ->enemy = attacker;
04920                         }
04921 
04922                         if ( ( targ->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL ) )
04923                         {
04924                                 //((CVehicleNPC *)targ->NPC)->m_ulFlags |= CVehicleNPC::VEH_BUCKING;
04925                         }
04926 
04927                         targ->m_pVehicle->m_iShields = targ->client->ps.stats[STAT_ARMOR];
04928                         G_VehUpdateShields( targ );
04929                         targ->m_pVehicle->m_iArmor -= take;
04930                         if ( targ->m_pVehicle->m_iArmor <= 0 ) 
04931                         {
04932                                 targ->s.eFlags |= EF_DEAD;
04933                                 targ->client->ps.eFlags |= EF_DEAD;
04934                                 targ->m_pVehicle->m_iArmor = 0;
04935                         }
04936                         if ( targ->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
04937                         {//get the last surf that was hit
04938                                 if ( targ->client && targ->client->g2LastSurfaceTime == level.time)
04939                                 {
04940                                         char hitSurface[MAX_QPATH];
04941 
04942                                         trap_G2API_GetSurfaceName(targ->ghoul2, targ->client->g2LastSurfaceHit, 0, hitSurface);
04943 
04944                                         if (hitSurface[0])
04945                                         {
04946                                                 surface = G_ShipSurfaceForSurfName( &hitSurface[0] );
04947 
04948                                                 if ( take && surface > 0 )
04949                                                 {//hit a certain part of the ship
04950                                                         int deathPoint = 0;
04951 
04952                                                         targ->locationDamage[surface] += take;
04953 
04954                                                         switch(surface)
04955                                                         {
04956                                                         case SHIPSURF_FRONT:
04957                                                                 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_front;
04958                                                                 break;
04959                                                         case SHIPSURF_BACK:
04960                                                                 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_back;
04961                                                                 break;
04962                                                         case SHIPSURF_RIGHT:
04963                                                                 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_right;
04964                                                                 break;
04965                                                         case SHIPSURF_LEFT:
04966                                                                 deathPoint = targ->m_pVehicle->m_pVehicleInfo->health_left;
04967                                                                 break;
04968                                                         default:
04969                                                                 break;
04970                                                         }
04971 
04972                                                         //presume 0 means it wasn't set and so it should never die.
04973                                                         if ( deathPoint )
04974                                                         {
04975                                                                 if ( targ->locationDamage[surface] >= deathPoint)
04976                                                                 { //this area of the ship is now dead
04977                                                                         if ( G_FlyVehicleDestroySurface( targ, surface ) )
04978                                                                         {//actually took off a surface
04979                                                                                 G_VehicleSetDamageLocFlags( targ, surface, deathPoint );
04980                                                                         }
04981                                                                 }
04982                                                                 else
04983                                                                 {
04984                                                                         G_VehicleSetDamageLocFlags( targ, surface, deathPoint );
04985                                                                 }
04986                                                         }
04987                                                 }
04988                                         }
04989                                 }
04990                         }
04991                         if ( targ->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL )
04992                         {
04993                                 /*
04994                                 if ( targ->m_pVehicle->m_iArmor <= 0 ) 
04995                                 {//vehicle all out of armor
04996                                         Vehicle_t *pVeh = targ->m_pVehicle;
04997                                         if ( pVeh->m_iDieTime == 0 )
04998                                         {//just start the flaming effect and explosion delay, if it's not going already...
04999                                                 pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, 0 );
05000                                         }
05001                                 }
05002                                 else*/
05003                                 if ( attacker 
05004                                                 //&& attacker->client 
05005                                                 && targ != attacker
05006                                                 && point 
05007                                                 && !VectorCompare( targ->client->ps.origin, point )
05008                                                 && targ->m_pVehicle->m_LandTrace.fraction >= 1.0f)
05009                                 {//just took a hit, knock us around
05010                                         vec3_t  vUp, impactDir;
05011                                         float   impactStrength = (damage/200.0f)*10.0f;
05012                                         float   dot = 0.0f;
05013                                         if ( impactStrength > 10.0f )
05014                                         {
05015                                                 impactStrength = 10.0f;
05016                                         }
05017                                         //pitch or roll us based on where we were hit
05018                                         AngleVectors( targ->m_pVehicle->m_vOrientation, NULL, NULL, vUp );
05019                                         VectorSubtract( point, targ->r.currentOrigin, impactDir );
05020                                         VectorNormalize( impactDir );
05021                                         if ( surface <= 0 )
05022                                         {//no surf guess where we were hit, then
05023                                                 vec3_t  vFwd, vRight;
05024                                                 AngleVectors( targ->m_pVehicle->m_vOrientation, vFwd, vRight, vUp );
05025                                                 dot = DotProduct( vRight, impactDir );
05026                                                 if ( dot > 0.4f )
05027                                                 {
05028                                                         surface = SHIPSURF_RIGHT;
05029                                                 }
05030                                                 else if ( dot < -0.4f )
05031                                                 {
05032                                                         surface = SHIPSURF_LEFT;
05033                                                 }
05034                                                 else
05035                                                 {
05036                                                         dot = DotProduct( vFwd, impactDir );
05037                                                         if ( dot > 0.0f )
05038                                                         {
05039                                                                 surface = SHIPSURF_FRONT;
05040                                                         }
05041                                                         else
05042                                                         {
05043                                                                 surface = SHIPSURF_BACK;
05044                                                         }
05045                                                 }
05046                                         }
05047                                         switch ( surface )
05048                                         {
05049                                         case SHIPSURF_FRONT:
05050                                                 dot = DotProduct( vUp, impactDir );
05051                                                 if ( dot > 0 )
05052                                                 {
05053                                                         targ->m_pVehicle->m_vOrientation[PITCH] += impactStrength;
05054                                                 }
05055                                                 else
05056                                                 {
05057                                                         targ->m_pVehicle->m_vOrientation[PITCH] -= impactStrength;
05058                                                 }
05059                                                 break;
05060                                         case SHIPSURF_BACK:
05061                                                 dot = DotProduct( vUp, impactDir );
05062                                                 if ( dot > 0 )
05063                                                 {
05064                                                         targ->m_pVehicle->m_vOrientation[PITCH] -= impactStrength;
05065                                                 }
05066                                                 else
05067                                                 {
05068                                                         targ->m_pVehicle->m_vOrientation[PITCH] += impactStrength;
05069                                                 }
05070                                                 break;
05071                                         case SHIPSURF_RIGHT:
05072                                                 dot = DotProduct( vUp, impactDir );
05073                                                 if ( dot > 0 )
05074                                                 {
05075                                                         targ->m_pVehicle->m_vOrientation[ROLL] -= impactStrength;
05076                                                 }
05077                                                 else
05078                                                 {
05079                                                         targ->m_pVehicle->m_vOrientation[ROLL] += impactStrength;
05080                                                 }
05081                                                 break;
05082                                         case SHIPSURF_LEFT:
05083                                                 dot = DotProduct( vUp, impactDir );
05084                                                 if ( dot > 0 )
05085                                                 {
05086                                                         targ->m_pVehicle->m_vOrientation[ROLL] += impactStrength;
05087                                                 }
05088                                                 else
05089                                                 {
05090                                                         targ->m_pVehicle->m_vOrientation[ROLL] -= impactStrength;
05091                                                 }
05092                                                 break;
05093                                         }
05094 
05095                                 }
05096                         }
05097                 }
05098         }
05099 
05100         if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT )
05101         {//FIXME: screw with non-animal vehicles, too?
05102                 if ( client )
05103                 {
05104                         if ( client->NPC_class == CLASS_VEHICLE 
05105                                 && targ->m_pVehicle
05106                                 && targ->m_pVehicle->m_pVehicleInfo
05107                                 && targ->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
05108                         {//all damage goes into the disruption of shields and systems
05109                                 take = 0;
05110                         }
05111                         else
05112                         {
05113 
05114                                 if (client->jetPackOn)
05115                                 { //disable jetpack temporarily
05116                                         Jetpack_Off(targ);
05117                                         client->jetPackToggleTime = level.time + Q_irand(3000, 10000);
05118                                 }
05119 
05120                                 if ( client->NPC_class == CLASS_PROTOCOL || client->NPC_class == CLASS_SEEKER ||
05121                                         client->NPC_class == CLASS_R2D2 || client->NPC_class == CLASS_R5D2 ||
05122                                         client->NPC_class == CLASS_MOUSE || client->NPC_class == CLASS_GONK )
05123                                 {
05124                                         // DEMP2 does more damage to these guys.
05125                                         take *= 2;
05126                                 }
05127                                 else if ( client->NPC_class == CLASS_PROBE || client->NPC_class == CLASS_INTERROGATOR ||
05128                                                         client->NPC_class == CLASS_MARK1 || client->NPC_class == CLASS_MARK2 || client->NPC_class == CLASS_SENTRY ||
05129                                                         client->NPC_class == CLASS_ATST )
05130                                 {
05131                                         // DEMP2 does way more damage to these guys.
05132                                         take *= 5;
05133                                 }
05134                                 else
05135                                 {
05136                                         if (take > 0)
05137                                         {
05138                                                 take /= 3;
05139                                                 if (take < 1)
05140                                                 {
05141                                                         take = 1;
05142                                                 }
05143                                         }
05144                                 }
05145                         }
05146                 }
05147         }
05148 
05149 #ifndef FINAL_BUILD
05150         if ( g_debugDamage.integer ) {
05151                 G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
05152                         targ->health, take, asave );
05153         }
05154 #endif
05155 
05156         // add to the damage inflicted on a player this frame
05157         // the total will be turned into screen blends and view angle kicks
05158         // at the end of the frame
05159         if ( client ) {
05160                 if ( attacker ) {
05161                         client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
05162                 } else {
05163                         client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
05164                 }
05165                 client->damage_armor += asave;
05166                 client->damage_blood += take;
05167                 client->damage_knockback += knockback;
05168                 if ( dir ) {
05169                         VectorCopy ( dir, client->damage_from );
05170                         client->damage_fromWorld = qfalse;
05171                 } else {
05172                         VectorCopy ( targ->r.currentOrigin, client->damage_from );
05173                         client->damage_fromWorld = qtrue;
05174                 }
05175 
05176                 if (attacker && attacker->client)
05177                 {
05178                         BotDamageNotification(client, attacker);
05179                 }
05180                 else if (inflictor && inflictor->client)
05181                 {
05182                         BotDamageNotification(client, inflictor);
05183                 }
05184         }
05185 
05186         // See if it's the player hurting the emeny flag carrier
05187         if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY) {
05188                 Team_CheckHurtCarrier(targ, attacker);
05189         }
05190 
05191         if (targ->client) {
05192                 // set the last client who damaged the target
05193                 targ->client->lasthurt_client = attacker->s.number;
05194                 targ->client->lasthurt_mod = mod;
05195         }
05196 
05197         if ( !(dflags & DAMAGE_NO_PROTECTION) ) 
05198         {//protect overridden by no_protection
05199                 if (take && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_PROTECT)))
05200                 {
05201                         if (targ->client->ps.fd.forcePower)
05202                         {
05203                                 int maxtake = take;
05204 
05205                                 //G_Sound(targ, CHAN_AUTO, protectHitSound);
05206                                 if (targ->client->forcePowerSoundDebounce < level.time)
05207                                 {
05208                                         G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT);
05209                                         targ->client->forcePowerSoundDebounce = level.time + 400;
05210                                 }
05211 
05212                                 if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1)
05213                                 {
05214                                         famt = 1;
05215                                         hamt = 0.40;
05216 
05217                                         if (maxtake > 100)
05218                                         {
05219                                                 maxtake = 100;
05220                                         }
05221                                 }
05222                                 else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_2)
05223                                 {
05224                                         famt = 0.5;
05225                                         hamt = 0.60;
05226 
05227                                         if (maxtake > 200)
05228                                         {
05229                                                 maxtake = 200;
05230                                         }
05231                                 }
05232                                 else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_3)
05233                                 {
05234                                         famt = 0.25;
05235                                         hamt = 0.80;
05236 
05237                                         if (maxtake > 400)
05238                                         {
05239                                                 maxtake = 400;
05240                                         }
05241                                 }
05242 
05243                                 if (!targ->client->ps.powerups[PW_FORCE_BOON])
05244                                 {
05245                                         targ->client->ps.fd.forcePower -= maxtake*famt;
05246                                 }
05247                                 else
05248                                 {
05249                                         targ->client->ps.fd.forcePower -= (maxtake*famt)/2;
05250                                 }
05251                                 subamt = (maxtake*hamt)+(take-maxtake);
05252                                 if (targ->client->ps.fd.forcePower < 0)
05253                                 {
05254                                         subamt += targ->client->ps.fd.forcePower;
05255                                         targ->client->ps.fd.forcePower = 0;
05256                                 }
05257                                 if (subamt)
05258                                 {
05259                                         take -= subamt;
05260 
05261                                         if (take < 0)
05262                                         {
05263                                                 take = 0;
05264                                         }
05265                                 }
05266                         }
05267                 }
05268         }
05269 
05270         if (shieldAbsorbed)
05271         {
05272                 /*
05273                 if ( targ->client->NPC_class == CLASS_VEHICLE )
05274                 {
05275                         targ->client->ps.electrifyTime = level.time + Q_irand( 500, 1000 );
05276                 }
05277                 else
05278                 */
05279                 {
05280                         gentity_t       *evEnt;
05281 
05282                         // Send off an event to show a shield shell on the player, pointing in the right direction.
05283                         //evEnt = G_TempEntity(vec3_origin, EV_SHIELD_HIT);
05284                         //rww - er.. what the? This isn't broadcast, why is it being set on vec3_origin?!
05285                         evEnt = G_TempEntity(targ->r.currentOrigin, EV_SHIELD_HIT);
05286                         evEnt->s.otherEntityNum = targ->s.number;
05287                         evEnt->s.eventParm = DirToByte(dir);
05288                         evEnt->s.time2=shieldAbsorbed;
05289         /*
05290                         shieldAbsorbed *= 20;
05291 
05292                         if (shieldAbsorbed > 1500)
05293                         {
05294                                 shieldAbsorbed = 1500;
05295                         }
05296                         if (shieldAbsorbed < 200)
05297                         {
05298                                 shieldAbsorbed = 200;
05299                         }
05300 
05301                         if (targ->client->ps.powerups[PW_SHIELDHIT] < (level.time + shieldAbsorbed))
05302                         {
05303                                 targ->client->ps.powerups[PW_SHIELDHIT] = level.time + shieldAbsorbed;
05304                         }
05305                         //flicker for as many ms as damage was absorbed (*20)
05306                         //therefore 10 damage causes 1/5 of a seond of flickering, whereas
05307                         //a full 100 causes 2 seconds (but is reduced to 1.5 seconds due to the max)
05308 
05309         */
05310                 }
05311         }
05312 
05313         // do the damage
05314         if (take) 
05315         {
05316                 if (targ->client && targ->s.number < MAX_CLIENTS &&
05317                         (mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT))
05318                 { //uh.. shock them or something. what the hell, I don't know.
05319             if (targ->client->ps.weaponTime <= 0)
05320                         { //yeah, we were supposed to be beta a week ago, I don't feel like
05321                                 //breaking the game so I'm gonna be safe and only do this only
05322                                 //if your weapon is not busy
05323                                 targ->client->ps.weaponTime = 2000;
05324                                 targ->client->ps.electrifyTime = level.time + 2000;
05325                                 if (targ->client->ps.weaponstate == WEAPON_CHARGING ||
05326                                         targ->client->ps.weaponstate == WEAPON_CHARGING_ALT)
05327                                 {
05328                                         targ->client->ps.weaponstate = WEAPON_READY;
05329                                 }
05330                         }
05331                 }
05332 
05333                 if ( !(dflags & DAMAGE_NO_PROTECTION) ) 
05334                 {//rage overridden by no_protection
05335                         if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client))
05336                         {
05337                                 take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]+1);
05338                         }
05339                 }
05340                 targ->health = targ->health - take;
05341 
05342                 if ( (targ->flags&FL_UNDYING) )
05343                 {//take damage down to 1, but never die
05344                         if ( targ->health < 1 )
05345                         {
05346                                 targ->health = 1;
05347                         }
05348                 }
05349 
05350                 if ( targ->client ) {
05351                         targ->client->ps.stats[STAT_HEALTH] = targ->health;
05352                 }
05353 
05354                 if ( !(dflags & DAMAGE_NO_PROTECTION) ) 
05355                 {//rage overridden by no_protection
05356                         if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client))
05357                         {
05358                                 if (targ->health <= 0)
05359                                 {
05360                                         targ->health = 1;
05361                                 }
05362                                 if (targ->client->ps.stats[STAT_HEALTH] <= 0)
05363                                 {
05364                                         targ->client->ps.stats[STAT_HEALTH] = 1;
05365                                 }
05366                         }
05367                 }
05368 
05369                 //We want to go ahead and set gPainHitLoc regardless of if we have a pain func,
05370                 //so we can adjust the location damage too.
05371                 if (targ->client && targ->ghoul2 && targ->client->g2LastSurfaceTime == level.time)
05372                 { //We updated the hit surface this frame, so it's valid.
05373                         char hitSurface[MAX_QPATH];
05374 
05375                         trap_G2API_GetSurfaceName(targ->ghoul2, targ->client->g2LastSurfaceHit, 0, hitSurface);
05376 
05377                         if (hitSurface[0])
05378                         {
05379                                 G_GetHitLocFromSurfName(targ, hitSurface, &gPainHitLoc, point, dir, vec3_origin, mod);
05380                         }
05381                         else
05382                         {
05383                                 gPainHitLoc = -1;
05384                         }
05385 
05386                         if (gPainHitLoc < HL_MAX && gPainHitLoc >= 0 && targ->locationDamage[gPainHitLoc] < Q3_INFINITE &&
05387                                 (targ->s.eType == ET_PLAYER || targ->s.NPC_class != CLASS_VEHICLE))
05388                         {
05389                                 targ->locationDamage[gPainHitLoc] += take;
05390 
05391                                 if (g_armBreakage.integer && !targ->client->ps.brokenLimbs &&
05392                                         targ->client->ps.stats[STAT_HEALTH] > 0 && targ->health > 0 &&
05393                                         !(targ->s.eFlags & EF_DEAD))
05394                                 { //check for breakage
05395                                         if (targ->locationDamage[HL_ARM_RT]+targ->locationDamage[HL_HAND_RT] >= 80)
05396                                         {
05397                                                 G_BreakArm(targ, BROKENLIMB_RARM);
05398                                         }
05399                                         else if (targ->locationDamage[HL_ARM_LT]+targ->locationDamage[HL_HAND_LT] >= 80)
05400                                         {
05401                                                 G_BreakArm(targ, BROKENLIMB_LARM);
05402                                         }
05403                                 }
05404                         }
05405                 }
05406                 else
05407                 {
05408                         gPainHitLoc = -1;
05409                 }
05410 
05411                 if (targ->maxHealth)
05412                 { //if this is non-zero this guy should be updated his s.health to send to the client
05413                         G_ScaleNetHealth(targ);
05414                 }
05415 
05416                 if ( targ->health <= 0 ) {
05417                         if ( client )
05418                         {
05419                                 targ->flags |= FL_NO_KNOCKBACK;
05420 
05421                                 if (point)
05422                                 {
05423                                         VectorCopy( point, targ->pos1 );
05424                                 }
05425                                 else
05426                                 {
05427                                         VectorCopy(targ->client->ps.origin, targ->pos1);
05428                                 }
05429                         }
05430                         else if (targ->s.eType == ET_NPC)
05431                         { //g2animent
05432                                 VectorCopy(point, targ->pos1);
05433                         }
05434 
05435                         if (targ->health < -999)
05436                                 targ->health = -999;
05437 
05438                         // If we are a breaking glass brush, store the damage point so we can do cool things with it.
05439                         if ( targ->r.svFlags & SVF_GLASS_BRUSH )
05440                         {
05441                                 VectorCopy( point, targ->pos1 );
05442                                 if (dir)
05443                                 {
05444                                         VectorCopy( dir, targ->pos2 );
05445                                 }
05446                                 else
05447                                 {
05448                                         VectorClear(targ->pos2);
05449                                 }
05450                         }
05451 
05452                         if (targ->s.eType == ET_NPC &&
05453                                 targ->client &&
05454                                 (targ->s.eFlags & EF_DEAD))
05455                         { //an NPC that's already dead. Maybe we can cut some more limbs off!
05456                                 if ( (mod == MOD_SABER || (mod == MOD_MELEE && G_HeavyMelee( attacker )) )//saber or heavy melee (claws)
05457                                         && take > 2
05458                                         && !(dflags&DAMAGE_NO_DISMEMBER) )
05459                                 {
05460                                         G_CheckForDismemberment(targ, attacker, targ->pos1, take, targ->client->ps.torsoAnim, qtrue);
05461                                 }
05462                         }
05463 
05464                         targ->enemy = attacker;
05465                         targ->die (targ, inflictor, attacker, take, mod);
05466                         G_ActivateBehavior( targ, BSET_DEATH );
05467                         return;
05468                 } 
05469                 else 
05470                 {
05471                         if ( g_debugMelee.integer )
05472                         {//getting hurt makes you let go of the wall
05473                                 if ( targ->client && (targ->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
05474                                 {
05475                                         G_LetGoOfWall( targ );
05476                                 }
05477                         }
05478                         if ( targ->pain ) 
05479                         {
05480                                 if (targ->s.eType != ET_NPC || mod != MOD_SABER || take > 1)
05481                                 { //don't even notify NPCs of pain if it's just idle saber damage
05482                                         gPainMOD = mod;
05483                                         if (point)
05484                                         {
05485                                                 VectorCopy(point, gPainPoint);
05486                                         }
05487                                         else
05488                                         {
05489                                                 VectorCopy(targ->r.currentOrigin, gPainPoint);
05490                                         }
05491                                         targ->pain (targ, attacker, take);
05492                                 }
05493                         }
05494                 }
05495 
05496                 G_LogWeaponDamage(attacker->s.number, mod, take);
05497         }
05498 
05499 }

void G_DeathAlert gentity_t victim,
gentity_t attacker
 

Definition at line 1868 of file g_combat.c.

References DEATH_ALERT_RADIUS, DEATH_ALERT_SOUND_RADIUS, G_AlertTeam(), and gentity_t.

Referenced by player_die().

01869 {//FIXME: with all the other alert stuff, do we really need this?
01870         G_AlertTeam( victim, attacker, DEATH_ALERT_RADIUS, DEATH_ALERT_SOUND_RADIUS );
01871 }

void G_Dismember gentity_t ent,
gentity_t enemy,
vec3_t  point,
int  limbType,
float  limbRollBase,
float  limbPitchBase,
int  deathAnim,
qboolean  postDeath
 

Definition at line 3311 of file g_combat.c.

References entityState_s::apos, BG_GetRootSurfNameWithVariant(), BG_InDeathAnim(), gentity_s::classname, gentity_s::client, gentity_s::clipmask, Com_sprintf(), entityShared_t::contents, CONTENTS_TRIGGER, entityShared_t::currentAngles, entityShared_t::currentOrigin, entityState_s::customRGBA, gentity_s::epGravFactor, gentity_s::epVelocity, ET_GENERAL, ET_NPC, entityState_s::eType, FRAMETIME, G2_MODEL_PART, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, entityState_s::g2radius, G_SetOrigin(), G_Spawn(), gentity_t, gentity_s::ghoul2, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, LimbThink(), LimbTouch(), MASK_SOLID, MAX_QPATH, entityShared_t::maxs, entityShared_t::mins, entityState_s::modelGhoul2, entityState_s::modelindex, gentity_s::nextthink, entityState_s::number, gclient_s::olderIsValid, gclient_s::olderSaberBase, entityState_s::otherEntityNum2, gentity_s::physicsObject, entityState_s::pos, gclient_s::ps, Q_irand(), Q_strncpyz(), qtrue, gentity_s::r, gentity_s::s, gentity_s::speed, SVF_USE_CURRENT_ORIGIN, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, playerState_s::torsoAnim, playerState_s::torsoTimer, gentity_s::touch, trap_G2API_GetSurfaceRenderStatus(), trap_G2API_SetSurfaceOnOff(), trap_LinkEntity(), trajectory_t::trBase, trajectory_t::trDelta, vec3_t, VectorAdd, VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, playerState_s::weapon, and WP_SABER.

Referenced by DismembermentByNum(), DismembermentTest(), G_CheckForDismemberment(), Rancor_Attack(), Rancor_Bite(), and Wampa_Slash().

03312 {
03313         vec3_t  newPoint, dir, vel;
03314         gentity_t *limb;
03315         char    limbName[MAX_QPATH];
03316         char    stubName[MAX_QPATH];
03317         char    stubCapName[MAX_QPATH];
03318 
03319         if (limbType == G2_MODELPART_HEAD)
03320         {
03321                 Q_strncpyz( limbName , "head", sizeof( limbName  ) );
03322                 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
03323         }
03324         else if (limbType == G2_MODELPART_WAIST)
03325         {
03326                 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
03327                 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
03328         }
03329         else if (limbType == G2_MODELPART_LARM)
03330         {
03331                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_arm", limbName, sizeof(limbName) );
03332                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03333                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
03334         }
03335         else if (limbType == G2_MODELPART_RARM)
03336         {
03337                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", limbName, sizeof(limbName) );
03338                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03339                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
03340         }
03341         else if (limbType == G2_MODELPART_RHAND)
03342         {
03343                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_hand", limbName, sizeof(limbName) );
03344                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", stubName, sizeof(stubName) );
03345                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
03346         }
03347         else if (limbType == G2_MODELPART_LLEG)
03348         {
03349                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_leg", limbName, sizeof(limbName) );
03350                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03351                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
03352         }
03353         else if (limbType == G2_MODELPART_RLEG)
03354         {
03355                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03356                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03357                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03358         }
03359         else
03360         {//umm... just default to the right leg, I guess (same as on client)
03361                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03362                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03363                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03364         }
03365 
03366         if (ent->ghoul2 && limbName && trap_G2API_GetSurfaceRenderStatus(ent->ghoul2, 0, limbName))
03367         { //is it already off? If so there's no reason to be doing it again, so get out of here.
03368                 return;
03369         }
03370 
03371         VectorCopy( point, newPoint );
03372         limb = G_Spawn();
03373         limb->classname = "playerlimb";
03374 
03375         /*
03376         if (limbType == G2_MODELPART_WAIST)
03377         { //slight hack
03378                 newPoint[2] += 1;
03379         }
03380         */
03381 
03382         G_SetOrigin( limb, newPoint );
03383         VectorCopy( newPoint, limb->s.pos.trBase );
03384         limb->think = LimbThink;
03385         limb->touch = LimbTouch;
03386         limb->speed = level.time + Q_irand(8000, 16000);
03387         limb->nextthink = level.time + FRAMETIME;
03388 
03389         limb->r.svFlags = SVF_USE_CURRENT_ORIGIN;
03390         limb->clipmask = MASK_SOLID;
03391         limb->r.contents = CONTENTS_TRIGGER;
03392         limb->physicsObject = qtrue;
03393         VectorSet( limb->r.mins, -6.0f, -6.0f, -3.0f );
03394         VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f );
03395 
03396         limb->s.g2radius = 200;
03397 
03398         limb->s.eType = ET_GENERAL;
03399         limb->s.weapon = G2_MODEL_PART;
03400         limb->s.modelGhoul2 = limbType;
03401         limb->s.modelindex = ent->s.number;
03402         if (!ent->client)
03403         {
03404                 limb->s.modelindex = -1;
03405                 limb->s.otherEntityNum2 = ent->s.number;
03406         }
03407 
03408         VectorClear(limb->s.apos.trDelta);
03409 
03410         if (ent->client)
03411         {
03412                 VectorCopy(ent->client->ps.viewangles, limb->r.currentAngles);
03413                 VectorCopy(ent->client->ps.viewangles, limb->s.apos.trBase);
03414         }
03415         else
03416         {
03417                 VectorCopy(ent->r.currentAngles, limb->r.currentAngles);
03418                 VectorCopy(ent->r.currentAngles, limb->s.apos.trBase);
03419         }
03420 
03421         //Set up the ExPhys values for the entity.
03422         limb->epGravFactor = 0;
03423         VectorClear(limb->epVelocity);
03424         VectorSubtract( point, ent->r.currentOrigin, dir );
03425         VectorNormalize( dir );
03426         if (ent->client)
03427         {
03428                 VectorCopy(ent->client->ps.velocity, vel);
03429         }
03430         else
03431         {
03432                 VectorCopy(ent->s.pos.trDelta, vel);
03433         }
03434         VectorMA( vel, 80, dir, limb->epVelocity );
03435 
03436         //add some vertical velocity
03437         if (limbType == G2_MODELPART_HEAD ||
03438                 limbType == G2_MODELPART_WAIST)
03439         {
03440                 limb->epVelocity[2] += 10;
03441         }
03442 
03443         if (enemy && enemy->client && ent && ent != enemy && ent->s.number != enemy->s.number &&
03444                 enemy->client->ps.weapon == WP_SABER && enemy->client->olderIsValid &&
03445                 (level.time - enemy->client->lastSaberStorageTime) < 200)
03446         { //The enemy has valid saber positions between this and last frame. Use them to factor in direction of the limb.
03447                 vec3_t dif;
03448                 float totalDistance;
03449                 const float distScale = 1.2f;
03450 
03451                 //scale down the initial velocity first, which is based on the speed of the limb owner.
03452                 //ExPhys object velocity operates on a slightly different scale than Q3-based physics velocity.
03453                 VectorScale(limb->epVelocity, 0.4f, limb->epVelocity);
03454 
03455                 VectorSubtract(enemy->client->lastSaberBase_Always, enemy->client->olderSaberBase, dif);
03456                 totalDistance = VectorNormalize(dif);
03457 
03458                 VectorScale(dif, totalDistance*distScale, dif);
03459                 VectorAdd(limb->epVelocity, dif, limb->epVelocity);
03460 
03461                 if (ent->client && (ent->client->ps.torsoTimer > 0 || !BG_InDeathAnim(ent->client->ps.torsoAnim)))
03462                 { //if he's done with his death anim we don't actually want the limbs going far
03463                         vec3_t preVel;
03464 
03465                         VectorCopy(limb->epVelocity, preVel);
03466                         preVel[2] = 0;
03467                         totalDistance = VectorNormalize(preVel);
03468 
03469                         if (totalDistance < 40.0f)
03470                         {
03471                                 float mAmt = 40.0f;//60.0f/totalDistance;
03472 
03473                                 limb->epVelocity[0] = preVel[0]*mAmt;
03474                                 limb->epVelocity[1] = preVel[1]*mAmt;
03475                         }
03476                 }
03477                 else if (ent->client)
03478                 {
03479                         VectorScale(limb->epVelocity, 0.3f, limb->epVelocity);
03480                 }
03481         }
03482 
03483         if (ent->s.eType == ET_NPC && ent->ghoul2 && limbName && stubCapName)
03484         { //if it's an npc remove these surfs on the server too. For players we don't even care cause there's no further dismemberment after death.
03485                 trap_G2API_SetSurfaceOnOff(ent->ghoul2, limbName, 0x00000100);
03486                 trap_G2API_SetSurfaceOnOff(ent->ghoul2, stubCapName, 0);
03487         }
03488 
03489         limb->s.customRGBA[0] = ent->s.customRGBA[0];
03490         limb->s.customRGBA[1] = ent->s.customRGBA[1];
03491         limb->s.customRGBA[2] = ent->s.customRGBA[2];
03492         limb->s.customRGBA[3] = ent->s.customRGBA[3];
03493 
03494         trap_LinkEntity( limb );
03495 }

qboolean G_FlyVehicleDestroySurface gentity_t veh,
int  surface
 

Referenced by G_Damage().

void G_GetDismemberBolt gentity_t self,
vec3_t  boltPoint,
int  limbType
 

Definition at line 3139 of file g_combat.c.

References entityState_s::angles, gentity_s::client, ENTITYNUM_NONE, EV_SABER_HIT, entityState_s::eventParm, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_TempEntity(), gentity_s::genericValue5, gentity_t, gentity_s::ghoul2, entityState_s::legsAnim, level, gentity_s::localAnimIndex, mdxaBone_t::matrix, gentity_s::modelScale, NULL, entityState_s::number, entityState_s::origin, playerState_s::origin, entityState_s::otherEntityNum, entityState_s::otherEntityNum2, gclient_s::ps, gentity_s::s, level_locals_t::time, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), vec3_t, VectorCopy, VectorNormalize(), playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, and YAW.

Referenced by DismembermentByNum(), DismembermentTest(), and G_CheckForDismemberment().

03140 {
03141         int useBolt = self->genericValue5;
03142         vec3_t properOrigin, properAngles, addVel;
03143         //vec3_t legAxis[3];
03144         mdxaBone_t      boltMatrix;
03145         float fVSpeed = 0;
03146         char *rotateBone = NULL;
03147 
03148         switch (limbType)
03149         {
03150         case G2_MODELPART_HEAD:
03151                 rotateBone = "cranium";
03152                 break;
03153         case G2_MODELPART_WAIST:
03154                 if (self->localAnimIndex <= 1)
03155                 { //humanoid
03156                         rotateBone = "thoracic";
03157                 }
03158                 else
03159                 {
03160                         rotateBone = "pelvis";
03161                 }
03162                 break;
03163         case G2_MODELPART_LARM:
03164                 rotateBone = "lradius";
03165                 break;
03166         case G2_MODELPART_RARM:
03167                 rotateBone = "rradius";
03168                 break;
03169         case G2_MODELPART_RHAND:
03170                 rotateBone = "rhand";
03171                 break;
03172         case G2_MODELPART_LLEG:
03173                 rotateBone = "ltibia";
03174                 break;
03175         case G2_MODELPART_RLEG:
03176                 rotateBone = "rtibia";
03177                 break;
03178         default:
03179                 rotateBone = "rtibia";
03180                 break;
03181         }
03182 
03183         useBolt = trap_G2API_AddBolt(self->ghoul2, 0, rotateBone);
03184 
03185         VectorCopy(self->client->ps.origin, properOrigin);
03186         VectorCopy(self->client->ps.viewangles, properAngles);
03187 
03188         //try to predict the origin based on velocity so it's more like what the client is seeing
03189         VectorCopy(self->client->ps.velocity, addVel);
03190         VectorNormalize(addVel);
03191 
03192         if (self->client->ps.velocity[0] < 0)
03193         {
03194                 fVSpeed += (-self->client->ps.velocity[0]);
03195         }
03196         else
03197         {
03198                 fVSpeed += self->client->ps.velocity[0];
03199         }
03200         if (self->client->ps.velocity[1] < 0)
03201         {
03202                 fVSpeed += (-self->client->ps.velocity[1]);
03203         }
03204         else
03205         {
03206                 fVSpeed += self->client->ps.velocity[1];
03207         }
03208         if (self->client->ps.velocity[2] < 0)
03209         {
03210                 fVSpeed += (-self->client->ps.velocity[2]);
03211         }
03212         else
03213         {
03214                 fVSpeed += self->client->ps.velocity[2];
03215         }
03216 
03217         fVSpeed *= 0.08;
03218 
03219         properOrigin[0] += addVel[0]*fVSpeed;
03220         properOrigin[1] += addVel[1]*fVSpeed;
03221         properOrigin[2] += addVel[2]*fVSpeed;
03222 
03223         properAngles[0] = 0;
03224         properAngles[1] = self->client->ps.viewangles[YAW];
03225         properAngles[2] = 0;
03226 
03227         trap_G2API_GetBoltMatrix(self->ghoul2, 0, useBolt, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03228 
03229         boltPoint[0] = boltMatrix.matrix[0][3];
03230         boltPoint[1] = boltMatrix.matrix[1][3];
03231         boltPoint[2] = boltMatrix.matrix[2][3];
03232 
03233         trap_G2API_GetBoltMatrix(self->ghoul2, 1, 0, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
03234 
03235         if (self->client && limbType == G2_MODELPART_RHAND)
03236         { //Make some saber hit sparks over the severed wrist area
03237                 vec3_t boltAngles;
03238                 gentity_t *te;
03239 
03240                 boltAngles[0] = -boltMatrix.matrix[0][1];
03241                 boltAngles[1] = -boltMatrix.matrix[1][1];
03242                 boltAngles[2] = -boltMatrix.matrix[2][1];
03243 
03244                 te = G_TempEntity( boltPoint, EV_SABER_HIT );
03245                 te->s.otherEntityNum = self->s.number;
03246                 te->s.otherEntityNum2 = ENTITYNUM_NONE;
03247                 te->s.weapon = 0;//saberNum
03248                 te->s.legsAnim = 0;//bladeNum
03249 
03250                 VectorCopy(boltPoint, te->s.origin);
03251                 VectorCopy(boltAngles, te->s.angles);
03252                 
03253                 if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
03254                 { //don't let it play with no direction
03255                         te->s.angles[1] = 1;
03256                 }
03257 
03258                 te->s.eventParm = 16; //lots of sparks
03259         }
03260 }

void G_GetDismemberLoc gentity_t self,
vec3_t  boltPoint,
int  limbType
 

Definition at line 3067 of file g_combat.c.

References AngleVectors(), entityShared_t::currentAngles, entityShared_t::currentOrigin, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, gentity_t, gentity_s::r, vec3_t, and VectorCopy.

Referenced by G_CheckForDismemberment().

03068 { //Just get the general area without using server-side ghoul2
03069         vec3_t fwd, right, up;
03070 
03071         AngleVectors(self->r.currentAngles, fwd, right, up);
03072 
03073         VectorCopy(self->r.currentOrigin, boltPoint);
03074 
03075         switch (limbType)
03076         {
03077         case G2_MODELPART_HEAD:
03078                 boltPoint[0] += up[0]*24;
03079                 boltPoint[1] += up[1]*24;
03080                 boltPoint[2] += up[2]*24;
03081                 break;
03082         case G2_MODELPART_WAIST:
03083                 boltPoint[0] += up[0]*4;
03084                 boltPoint[1] += up[1]*4;
03085                 boltPoint[2] += up[2]*4;
03086                 break;
03087         case G2_MODELPART_LARM:
03088                 boltPoint[0] += up[0]*18;
03089                 boltPoint[1] += up[1]*18;
03090                 boltPoint[2] += up[2]*18;
03091 
03092                 boltPoint[0] -= right[0]*10;
03093                 boltPoint[1] -= right[1]*10;
03094                 boltPoint[2] -= right[2]*10;
03095                 break;
03096         case G2_MODELPART_RARM:
03097                 boltPoint[0] += up[0]*18;
03098                 boltPoint[1] += up[1]*18;
03099                 boltPoint[2] += up[2]*18;
03100 
03101                 boltPoint[0] += right[0]*10;
03102                 boltPoint[1] += right[1]*10;
03103                 boltPoint[2] += right[2]*10;
03104                 break;
03105         case G2_MODELPART_RHAND:
03106                 boltPoint[0] += up[0]*8;
03107                 boltPoint[1] += up[1]*8;
03108                 boltPoint[2] += up[2]*8;
03109 
03110                 boltPoint[0] += right[0]*10;
03111                 boltPoint[1] += right[1]*10;
03112                 boltPoint[2] += right[2]*10;
03113                 break;
03114         case G2_MODELPART_LLEG:
03115                 boltPoint[0] -= up[0]*4;
03116                 boltPoint[1] -= up[1]*4;
03117                 boltPoint[2] -= up[2]*4;
03118 
03119                 boltPoint[0] -= right[0]*10;
03120                 boltPoint[1] -= right[1]*10;
03121                 boltPoint[2] -= right[2]*10;
03122                 break;
03123         case G2_MODELPART_RLEG:
03124                 boltPoint[0] -= up[0]*4;
03125                 boltPoint[1] -= up[1]*4;
03126                 boltPoint[2] -= up[2]*4;
03127 
03128                 boltPoint[0] += right[0]*10;
03129                 boltPoint[1] += right[1]*10;
03130                 boltPoint[2] += right[2]*10;
03131                 break;
03132         default:
03133                 break;
03134         }
03135 
03136         return;
03137 }

int G_GetHitLocation gentity_t target,
vec3_t  ppoint
 

Definition at line 45 of file g_combat.c.

References entityShared_t::absmax, entityShared_t::absmin, AngleVectors(), gentity_s::client, entityShared_t::currentAngles, DotProduct, fabs(), gentity_t, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, entityShared_t::maxs, entityShared_t::mins, gentity_s::r, vec3_origin, vec3_t, VectorAdd, VectorCopy, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, and YAW.

Referenced by G_CheckForDismemberment(), G_LocationBasedDamageModifier(), G_PickDeathAnim(), and WP_DisruptorAltFire().

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 }

qboolean G_GetHitLocFromSurfName gentity_t ent,
const char *  surfName,
int *  hitLoc,
vec3_t  point,
vec3_t  dir,
vec3_t  bladeDir,
int  mod
 

Definition at line 3632 of file g_combat.c.

References AngleVectors(), renderInfo_s::boltValidityTime, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DotProduct, g_dismember, gentity_t, gentity_s::ghoul2, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_GENERIC1, HL_GENERIC2, HL_GENERIC3, HL_GENERIC4, HL_GENERIC5, HL_GENERIC6, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MOD_SABER, gentity_s::modelScale, NEGATIVE_Y, gclient_s::NPC_class, NULL, ORIGIN, playerState_s::origin, gclient_s::ps, Q_stricmp(), Q_strncmp(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, renderInfo_s::torsoAngles, renderInfo_s::torsoPoint, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), UpdateClientRenderBolts(), vec3_t, VectorSet, VectorSubtract, playerState_s::viewangles, and YAW.

Referenced by G_CheckForDismemberment(), G_Damage(), and G_LocationBasedDamageModifier().

03633 {
03634         qboolean dismember = qfalse;
03635         int actualTime;
03636         int kneeLBolt = -1;
03637         int kneeRBolt = -1;
03638         int handRBolt = -1;
03639         int handLBolt = -1;
03640         int footRBolt = -1;
03641         int footLBolt = -1;
03642 
03643         *hitLoc = HL_NONE;
03644 
03645         if ( !surfName || !surfName[0] )
03646         {
03647                 return qfalse;
03648         }
03649 
03650         if( !ent->client )
03651         {
03652                 return qfalse;
03653         }
03654 
03655         if (!point)
03656         {
03657                 return qfalse;
03658         }
03659 
03660         if ( ent->client 
03661                 && ( ent->client->NPC_class == CLASS_R2D2 
03662                         || ent->client->NPC_class == CLASS_R2D2 
03663                         || ent->client->NPC_class == CLASS_GONK
03664                         || ent->client->NPC_class == CLASS_MOUSE
03665                         || ent->client->NPC_class == CLASS_SENTRY
03666                         || ent->client->NPC_class == CLASS_INTERROGATOR
03667                         || ent->client->NPC_class == CLASS_SENTRY
03668                         || ent->client->NPC_class == CLASS_PROBE ) )
03669         {//we don't care about per-surface hit-locations or dismemberment for these guys 
03670                 return qfalse;
03671         }
03672 
03673         if (ent->localAnimIndex <= 1)
03674         { //humanoid
03675                 handLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
03676                 handRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
03677                 kneeLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_l_knee");
03678                 kneeRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_r_knee");
03679                 footLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
03680                 footRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
03681         }
03682 
03683         if ( ent->client && (ent->client->NPC_class == CLASS_ATST) )
03684         {
03685                 //FIXME: almost impossible to hit these... perhaps we should
03686                 //              check for splashDamage and do radius damage to these parts?
03687                 //              Or, if we ever get bbox G2 traces, that may fix it, too
03688                 if (!Q_stricmp("head_light_blaster_cann",surfName))
03689                 {
03690                         *hitLoc = HL_ARM_LT;
03691                 }
03692                 else if (!Q_stricmp("head_concussion_charger",surfName))
03693                 {
03694                         *hitLoc = HL_ARM_RT;
03695                 }
03696                 return(qfalse);
03697         }
03698         else if ( ent->client && (ent->client->NPC_class == CLASS_MARK1) )
03699         {
03700                 if (!Q_stricmp("l_arm",surfName))
03701                 {
03702                         *hitLoc = HL_ARM_LT;
03703                 }
03704                 else if (!Q_stricmp("r_arm",surfName))
03705                 {
03706                         *hitLoc = HL_ARM_RT;
03707                 }
03708                 else if (!Q_stricmp("torso_front",surfName))
03709                 {
03710                         *hitLoc = HL_CHEST;
03711                 }
03712                 else if (!Q_stricmp("torso_tube1",surfName))
03713                 {
03714                         *hitLoc = HL_GENERIC1;
03715                 }
03716                 else if (!Q_stricmp("torso_tube2",surfName))
03717                 {
03718                         *hitLoc = HL_GENERIC2;
03719                 }
03720                 else if (!Q_stricmp("torso_tube3",surfName))
03721                 {
03722                         *hitLoc = HL_GENERIC3;
03723                 }
03724                 else if (!Q_stricmp("torso_tube4",surfName))
03725                 {
03726                         *hitLoc = HL_GENERIC4;
03727                 }
03728                 else if (!Q_stricmp("torso_tube5",surfName))
03729                 {
03730                         *hitLoc = HL_GENERIC5;
03731                 }
03732                 else if (!Q_stricmp("torso_tube6",surfName))
03733                 {
03734                         *hitLoc = HL_GENERIC6;
03735                 }
03736                 return(qfalse);
03737         }
03738         else if ( ent->client && (ent->client->NPC_class == CLASS_MARK2) )
03739         {
03740                 if (!Q_stricmp("torso_canister1",surfName))
03741                 {
03742                         *hitLoc = HL_GENERIC1;
03743                 }
03744                 else if (!Q_stricmp("torso_canister2",surfName))
03745                 {
03746                         *hitLoc = HL_GENERIC2;
03747                 }
03748                 else if (!Q_stricmp("torso_canister3",surfName))
03749                 {
03750                         *hitLoc = HL_GENERIC3;
03751                 }
03752                 return(qfalse);
03753         }
03754         else if ( ent->client && (ent->client->NPC_class == CLASS_GALAKMECH) )
03755         {
03756                 if (!Q_stricmp("torso_antenna",surfName)||!Q_stricmp("torso_antenna_base",surfName))
03757                 {
03758                         *hitLoc = HL_GENERIC1;
03759                 }
03760                 else if (!Q_stricmp("torso_shield",surfName))
03761                 {
03762                         *hitLoc = HL_GENERIC2;
03763                 }
03764                 else
03765                 {
03766                         *hitLoc = HL_CHEST;
03767                 }
03768                 return(qfalse);
03769         }
03770 
03771         //FIXME: check the hitLoc and hitDir against the cap tag for the place 
03772         //where the split will be- if the hit dir is roughly perpendicular to 
03773         //the direction of the cap, then the split is allowed, otherwise we
03774         //hit it at the wrong angle and should not dismember...
03775         actualTime = level.time;
03776         if ( !Q_strncmp( "hips", surfName, 4 ) )
03777         {//FIXME: test properly for legs
03778                 *hitLoc = HL_WAIST;
03779                 if ( ent->client != NULL && ent->ghoul2 )
03780                 {
03781                         mdxaBone_t      boltMatrix;
03782                         vec3_t  tagOrg, angles;
03783 
03784                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03785                         if (kneeLBolt>=0)
03786                         {
03787                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeLBolt, 
03788                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03789                                                                 actualTime, NULL, ent->modelScale );
03790                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03791                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03792                                 {//actually hit the knee
03793                                         *hitLoc = HL_LEG_LT;
03794                                 }
03795                         }
03796                         if (*hitLoc == HL_WAIST)
03797                         {
03798                                 if (kneeRBolt>=0)
03799                                 {
03800                                         trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeRBolt, 
03801                                                                         &boltMatrix, angles, ent->r.currentOrigin,
03802                                                                         actualTime, NULL, ent->modelScale );
03803                                         BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03804                                         if ( DistanceSquared( point, tagOrg ) < 100 )
03805                                         {//actually hit the knee
03806                                                 *hitLoc = HL_LEG_RT;
03807                                         }
03808                                 }
03809                         }
03810                 }
03811         }
03812         else if ( !Q_strncmp( "torso", surfName, 5 ) )
03813         {
03814                 if ( !ent->client )
03815                 {
03816                         *hitLoc = HL_CHEST;
03817                 }
03818                 else
03819                 {
03820                         vec3_t  t_fwd, t_rt, t_up, dirToImpact;
03821                         float frontSide, rightSide, upSide;
03822                         AngleVectors( ent->client->renderInfo.torsoAngles, t_fwd, t_rt, t_up );
03823 
03824                         if (ent->client->renderInfo.boltValidityTime != level.time)
03825                         {
03826                                 vec3_t renderAng;
03827 
03828                                 renderAng[0] = 0;
03829                                 renderAng[1] = ent->client->ps.viewangles[YAW];
03830                                 renderAng[2] = 0;
03831 
03832                                 UpdateClientRenderBolts(ent, ent->client->ps.origin, renderAng);
03833                         }
03834 
03835                         VectorSubtract( point, ent->client->renderInfo.torsoPoint, dirToImpact );
03836                         frontSide = DotProduct( t_fwd, dirToImpact );
03837                         rightSide = DotProduct( t_rt, dirToImpact );
03838                         upSide = DotProduct( t_up, dirToImpact );
03839                         if ( upSide < -10 )
03840                         {//hit at waist
03841                                 *hitLoc = HL_WAIST;
03842                         }
03843                         else
03844                         {//hit on upper torso
03845                                 if ( rightSide > 4 )
03846                                 {
03847                                         *hitLoc = HL_ARM_RT;
03848                                 }
03849                                 else if ( rightSide < -4 )
03850                                 {
03851                                         *hitLoc = HL_ARM_LT;
03852                                 }
03853                                 else if ( rightSide > 2 )
03854                                 {
03855                                         if ( frontSide > 0 )
03856                                         {
03857                                                 *hitLoc = HL_CHEST_RT;
03858                                         }
03859                                         else
03860                                         {
03861                                                 *hitLoc = HL_BACK_RT;
03862                                         }
03863                                 }
03864                                 else if ( rightSide < -2 )
03865                                 {
03866                                         if ( frontSide > 0 )
03867                                         {
03868                                                 *hitLoc = HL_CHEST_LT;
03869                                         }
03870                                         else
03871                                         {
03872                                                 *hitLoc = HL_BACK_LT;
03873                                         }
03874                                 }
03875                                 else if ( upSide > -3 && mod == MOD_SABER )
03876                                 {
03877                                         *hitLoc = HL_HEAD;
03878                                 }
03879                                 else if ( frontSide > 0 )
03880                                 {
03881                                         *hitLoc = HL_CHEST;
03882                                 }
03883                                 else
03884                                 {
03885                                         *hitLoc = HL_BACK;
03886                                 }
03887                         }
03888                 }
03889         }
03890         else if ( !Q_strncmp( "head", surfName, 4 ) )
03891         {
03892                 *hitLoc = HL_HEAD;
03893         }
03894         else if ( !Q_strncmp( "r_arm", surfName, 5 ) )
03895         {
03896                 *hitLoc = HL_ARM_RT;
03897                 if ( ent->client != NULL && ent->ghoul2 )
03898                 {
03899                         mdxaBone_t      boltMatrix;
03900                         vec3_t  tagOrg, angles;
03901 
03902                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03903                         if (handRBolt>=0)
03904                         {
03905                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handRBolt, 
03906                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03907                                                                 actualTime, NULL, ent->modelScale );
03908                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03909                                 if ( DistanceSquared( point, tagOrg ) < 256 )
03910                                 {//actually hit the hand
03911                                         *hitLoc = HL_HAND_RT;
03912                                 }
03913                         }
03914                 }
03915         }
03916         else if ( !Q_strncmp( "l_arm", surfName, 5 ) )
03917         {
03918                 *hitLoc = HL_ARM_LT;
03919                 if ( ent->client != NULL && ent->ghoul2 )
03920                 {
03921                         mdxaBone_t      boltMatrix;
03922                         vec3_t  tagOrg, angles;
03923 
03924                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03925                         if (handLBolt>=0)
03926                         {
03927                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handLBolt, 
03928                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03929                                                                 actualTime, NULL, ent->modelScale );
03930                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03931                                 if ( DistanceSquared( point, tagOrg ) < 256 )
03932                                 {//actually hit the hand
03933                                         *hitLoc = HL_HAND_LT;
03934                                 }
03935                         }
03936                 }
03937         }
03938         else if ( !Q_strncmp( "r_leg", surfName, 5 ) )
03939         {
03940                 *hitLoc = HL_LEG_RT;
03941                 if ( ent->client != NULL && ent->ghoul2 )
03942                 {
03943                         mdxaBone_t      boltMatrix;
03944                         vec3_t  tagOrg, angles;
03945 
03946                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03947                         if (footRBolt>=0)
03948                         {
03949                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footRBolt, 
03950                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03951                                                                 actualTime, NULL, ent->modelScale );
03952                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03953                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03954                                 {//actually hit the foot
03955                                         *hitLoc = HL_FOOT_RT;
03956                                 }
03957                         }
03958                 }
03959         }
03960         else if ( !Q_strncmp( "l_leg", surfName, 5 ) )
03961         {
03962                 *hitLoc = HL_LEG_LT;
03963                 if ( ent->client != NULL && ent->ghoul2 )
03964                 {
03965                         mdxaBone_t      boltMatrix;
03966                         vec3_t  tagOrg, angles;
03967 
03968                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03969                         if (footLBolt>=0)
03970                         {
03971                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footLBolt, 
03972                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03973                                                                 actualTime, NULL, ent->modelScale );
03974                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03975                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03976                                 {//actually hit the foot
03977                                         *hitLoc = HL_FOOT_LT;
03978                                 }
03979                         }
03980                 }
03981         }
03982         else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) )
03983         {//right hand or weapon
03984                 *hitLoc = HL_HAND_RT;
03985         }
03986         else if ( !Q_strncmp( "l_hand", surfName, 6 ) )
03987         {
03988                 *hitLoc = HL_HAND_LT;
03989         }
03990         /*
03991 #ifdef _DEBUG
03992         else
03993         {
03994                 Com_Printf( "ERROR: surface %s does not belong to any hitLocation!!!\n", surfName );
03995         }
03996 #endif //_DEBUG
03997         */
03998 
03999         //if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered )
04000         if (g_dismember.integer == 100)
04001         { //full probability...
04002                 if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL )
04003                 {
04004                         dismember = qtrue;
04005                 }
04006                 else if ( dir && (dir[0] || dir[1] || dir[2]) &&
04007                         bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) )
04008                 {//we care about direction (presumably for dismemberment)
04009                         //if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) )
04010                         if (1) //Fix me?
04011                         {//either we don't care about probabilties or the probability let us continue
04012                                 char *tagName = NULL;
04013                                 float   aoa = 0.5f;
04014                                 //dir must be roughly perpendicular to the hitLoc's cap bolt
04015                                 switch ( *hitLoc )
04016                                 {
04017                                         case HL_LEG_RT:
04018                                                 tagName = "*hips_cap_r_leg";
04019                                                 break;
04020                                         case HL_LEG_LT:
04021                                                 tagName = "*hips_cap_l_leg";
04022                                                 break;
04023                                         case HL_WAIST:
04024                                                 tagName = "*hips_cap_torso";
04025                                                 aoa = 0.25f;
04026                                                 break;
04027                                         case HL_CHEST_RT:
04028                                         case HL_ARM_RT:
04029                                         case HL_BACK_LT:
04030                                                 tagName = "*torso_cap_r_arm";
04031                                                 break;
04032                                         case HL_CHEST_LT:
04033                                         case HL_ARM_LT:
04034                                         case HL_BACK_RT:
04035                                                 tagName = "*torso_cap_l_arm";
04036                                                 break;
04037                                         case HL_HAND_RT:
04038                                                 tagName = "*r_arm_cap_r_hand";
04039                                                 break;
04040                                         case HL_HAND_LT:
04041                                                 tagName = "*l_arm_cap_l_hand";
04042                                                 break;
04043                                         case HL_HEAD:
04044                                                 tagName = "*torso_cap_head";
04045                                                 aoa = 0.25f;
04046                                                 break;
04047                                         case HL_CHEST:
04048                                         case HL_BACK:
04049                                         case HL_FOOT_RT:
04050                                         case HL_FOOT_LT:
04051                                         default:
04052                                                 //no dismemberment possible with these, so no checks needed
04053                                                 break;
04054                                 }
04055                                 if ( tagName )
04056                                 {
04057                                         int tagBolt = trap_G2API_AddBolt( ent->ghoul2, 0, tagName );
04058                                         if ( tagBolt != -1 )
04059                                         {
04060                                                 mdxaBone_t      boltMatrix;
04061                                                 vec3_t  tagOrg, tagDir, angles;
04062 
04063                                                 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
04064                                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, tagBolt, 
04065                                                                                 &boltMatrix, angles, ent->r.currentOrigin,
04066                                                                                 actualTime, NULL, ent->modelScale );
04067                                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
04068                                                 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, tagDir );
04069                                                 if ( DistanceSquared( point, tagOrg ) < 256 )
04070                                                 {//hit close
04071                                                         float dot = DotProduct( dir, tagDir );
04072                                                         if ( dot < aoa && dot > -aoa )
04073                                                         {//hit roughly perpendicular
04074                                                                 dot = DotProduct( bladeDir, tagDir );
04075                                                                 if ( dot < aoa && dot > -aoa )
04076                                                                 {//blade was roughly perpendicular
04077                                                                         dismember = qtrue;
04078                                                                 }
04079                                                         }
04080                                                 }
04081                                         }
04082                                 }
04083                         }
04084                 }
04085                 else
04086                 { //hmm, no direction supplied.
04087                         dismember = qtrue;
04088                 }
04089         }
04090         return dismember;
04091 }

int G_GetHitQuad gentity_t self,
vec3_t  hitloc
 

Definition at line 3546 of file g_combat.c.

References AngleVectors(), entityState_s::apos, gentity_s::client, DotProduct, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RLEG, gentity_t, gPainHitLoc, NULL, playerState_s::origin, entityState_s::pos, gclient_s::ps, gentity_s::s, trajectory_t::trBase, vec3_t, VectorCopy, VectorNormalize(), VectorSubtract, playerState_s::viewangles, and playerState_s::viewheight.

Referenced by G_CheckForDismemberment().

03547 {
03548         vec3_t diff, fwdangles={0,0,0}, right;
03549         vec3_t clEye;
03550         float rightdot;
03551         float zdiff;
03552         int hitLoc = gPainHitLoc;
03553 
03554         if (self->client)
03555         {
03556                 VectorCopy(self->client->ps.origin, clEye);
03557                 clEye[2] += self->client->ps.viewheight;
03558         }
03559         else
03560         {
03561                 VectorCopy(self->s.pos.trBase, clEye);
03562                 clEye[2] += 16;
03563         }
03564 
03565