diff options
Diffstat (limited to 'src/game/g_combat.c')
-rw-r--r-- | src/game/g_combat.c | 1193 |
1 files changed, 0 insertions, 1193 deletions
diff --git a/src/game/g_combat.c b/src/game/g_combat.c deleted file mode 100644 index b98654e7..00000000 --- a/src/game/g_combat.c +++ /dev/null @@ -1,1193 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// g_combat.c - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - - -/* -============ -AddScore - -Adds score to both the client and his team -============ -*/ -void AddScore( gentity_t *ent, int score ) { - if ( !ent->client ) { - return; - } - // no scoring during pre-match warmup - if ( level.warmupTime ) { - return; - } - ent->client->ps.persistant[PERS_SCORE] += score; - if (g_gametype.integer == GT_TEAM) - level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score; - CalculateRanks(); -} - - -/* -============ -AddPoints - -Adds points to both the client and his team -============ -*/ -void AddPoints( gentity_t *ent, int score ) -{ - if ( !ent->client ) { - return; - } - // no scoring during pre-match warmup - if ( level.warmupTime ) { - return; - } - ent->client->ps.persistant[PERS_POINTS] += score; - ent->client->ps.persistant[PERS_TOTALPOINTS] += score; - - /*if (g_gametype.integer == GT_TEAM) - level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score; - CalculateRanks();*/ -} - - -/* -============ -CalculatePoints - -Calculates the points to given to a client -============ -*/ -int CalculatePoints( gentity_t *victim, gentity_t *attacker ) -{ - int victim_value, attacker_value; - - if( !victim->client || !attacker->client ) - return 0; - - /*switch( victim->client->ps.stats[STAT_PCLASS] ) - { - case PCL_D_BUILDER: - victim_value = 1; - break; - case PCL_H_BUILDER: - victim_value = 1; - break; - case PCL_D_BASE: - victim_value = 2; - break; - case PCL_H_BASE: - victim_value = 2; - break; - case PCL_D_OFF1: - victim_value = 3; - break; - case PCL_H_OFF1: - victim_value = 3; - break; - case PCL_D_OFF2: - victim_value = 4; - break; - case PCL_H_OFF2: - victim_value = 4; - break; - case PCL_D_OFF3: - victim_value = 5; - break; - case PCL_H_OFF3: - victim_value = 5; - break; - case PCL_D_OFF4: - victim_value = 6; - break; - case PCL_H_OFF4: - victim_value = 6; - break; - case PCL_D_OFF5: - victim_value = 7; - break; - case PCL_H_OFF5: - victim_value = 7; - break; - case PCL_D_OFF6: - victim_value = 8; - break; - case PCL_H_OFF6: - victim_value = 8; - break; - case PCL_D_OFF7: - victim_value = 9; - break; - case PCL_H_OFF7: - victim_value = 9; - break; - case PCL_D_OFF8: - victim_value = 10; - break; - case PCL_H_OFF8: - victim_value = 10; - break; - default: - victim_value = 1; - } - - switch( attacker->client->ps.stats[STAT_PCLASS] ) - { - case PCL_D_BUILDER: - attacker_value = 1; - break; - case PCL_H_BUILDER: - attacker_value = 1; - break; - case PCL_D_BASE: - attacker_value = 2; - break; - case PCL_H_BASE: - attacker_value = 2; - break; - case PCL_D_OFF1: - attacker_value = 3; - break; - case PCL_H_OFF1: - attacker_value = 3; - break; - case PCL_D_OFF2: - attacker_value = 4; - break; - case PCL_H_OFF2: - attacker_value = 4; - break; - case PCL_D_OFF3: - attacker_value = 5; - break; - case PCL_H_OFF3: - attacker_value = 5; - break; - case PCL_D_OFF4: - attacker_value = 6; - break; - case PCL_H_OFF4: - attacker_value = 6; - break; - case PCL_D_OFF5: - attacker_value = 7; - break; - case PCL_H_OFF5: - attacker_value = 7; - break; - case PCL_D_OFF6: - attacker_value = 8; - break; - case PCL_H_OFF6: - attacker_value = 8; - break; - case PCL_D_OFF7: - attacker_value = 9; - break; - case PCL_H_OFF7: - attacker_value = 9; - break; - case PCL_D_OFF8: - attacker_value = 10; - break; - case PCL_H_OFF8: - attacker_value = 10; - break; - default: - attacker_value = 1; - } - - return ( victim_value / attacker_value ) * 10;*/ - - return 1; - -} - - -/* -================= -TossClientItems - -Toss the weapon and powerups for the killed player -================= -*/ -void TossClientItems( gentity_t *self ) { - gitem_t *item; - int weapon; - float angle; - int i; - gentity_t *drop; - int ammo, clips, maxclips; - - // drop the weapon if not a gauntlet or machinegun - weapon = self->s.weapon; - - BG_unpackAmmoArray( weapon, self->client->ps.ammo, self->client->ps.powerups, &ammo, &clips, &maxclips ); - - // make a special check to see if they are changing to a new - // weapon that isn't the mg or gauntlet. Without this, a client - // can pick up a weapon, be killed, and not drop the weapon because - // their weapon change hasn't completed yet and they are still holding the MG. - if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) { - if ( self->client->ps.weaponstate == WEAPON_DROPPING ) { - weapon = self->client->pers.cmd.weapon; - } - if ( !BG_gotWeapon( weapon, self->client->ps.stats ) ) { - weapon = WP_NONE; - } - } - - if( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK && - ( ammo > 0 || clips > 0 ) ) { - // find the item type for this weapon - item = BG_FindItemForWeapon( weapon ); - - //TA: never drop weapons... - // spawn the item - //Drop_Item( self, item, 0 ); - } - - // drop all the powerups if not in teamplay - if ( g_gametype.integer != GT_TEAM ) { - angle = 45; - /*for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) { - if ( self->client->ps.powerups[ i ] > level.time ) { - item = BG_FindItemForPowerup( i ); - if ( !item ) { - continue; - } - //TA: ...or powerups - /*drop = Drop_Item( self, item, angle ); - // decide how many seconds it has left - drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000; - if ( drop->count < 1 ) { - drop->count = 1; - } - angle += 45; - } - }*/ - } -} - - -/* -================== -LookAtKiller -================== -*/ -void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) { - vec3_t dir; - vec3_t angles; - - if ( attacker && attacker != self ) { - VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir); - } else if ( inflictor && inflictor != self ) { - VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir); - } else { - self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW]; - return; - } - - self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir ); - - angles[YAW] = vectoyaw ( dir ); - angles[PITCH] = 0; - angles[ROLL] = 0; -} - -/* -================== -GibEntity -================== -*/ -void GibEntity( gentity_t *self, int killer ) { - G_AddEvent( self, EV_GIB_PLAYER, killer ); - self->takedamage = qfalse; - self->s.eType = ET_INVISIBLE; - self->r.contents = 0; -} - -/* -================== -body_die -================== -*/ -void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { - if ( self->health > GIB_HEALTH ) { - return; - } - if ( !g_blood.integer ) { - self->health = GIB_HEALTH+1; - return; - } - - GibEntity( self, 0 ); -} - - -// these are just for logging, the client prints its own messages -char *modNames[] = { - "MOD_UNKNOWN", - "MOD_SHOTGUN", - "MOD_GAUNTLET", - "MOD_MACHINEGUN", - "MOD_CHAINGUN", - "MOD_GRENADE", - "MOD_GRENADE_SPLASH", - "MOD_ROCKET", - "MOD_ROCKET_SPLASH", - "MOD_FLAMER", - "MOD_FLAMER_SPLASH", - "MOD_RAILGUN", - "MOD_LIGHTNING", - "MOD_BFG", - "MOD_BFG_SPLASH", - "MOD_WATER", - "MOD_SLIME", - "MOD_LAVA", - "MOD_CRUSH", - "MOD_TELEFRAG", - "MOD_FALLING", - "MOD_SUICIDE", - "MOD_TARGET_LASER", - "MOD_TRIGGER_HURT", - "MOD_GRAPPLE", - "MOD_VENOM", - "MOD_HSPAWN", - "MOD_ASPAWN" -}; - - -/* -================== -CheckAlmostCapture -================== -*/ -void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) { - gentity_t *ent; - vec3_t dir; - char *classname; - - // if this player was carrying a flag - /*if ( self->client->ps.powerups[PW_REDFLAG] || - self->client->ps.powerups[PW_BLUEFLAG] || - self->client->ps.powerups[PW_NEUTRALFLAG] ) { - // get the goal flag this player should have been going for - if ( g_gametype.integer == GT_CTF ) { - if ( self->client->sess.sessionTeam == TEAM_DROIDS ) { - classname = "team_CTF_blueflag"; - } - else { - classname = "team_CTF_redflag"; - } - } - else { - if ( self->client->sess.sessionTeam == TEAM_DROIDS ) { - classname = "team_CTF_redflag"; - } - else { - classname = "team_CTF_blueflag"; - } - } - ent = NULL; - do - { - ent = G_Find(ent, FOFS(classname), classname); - } while (ent && (ent->flags & FL_DROPPED_ITEM)); - // if we found the destination flag and it's not picked up - if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) { - // if the player was *very* close - VectorSubtract( self->client->ps.origin, ent->s.origin, dir ); - if ( VectorLength(dir) < 200 ) { - self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT; - if ( attacker->client ) { - attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT; - } - } - } - }*/ -} - -/* -================== -CheckAlmostScored -================== -*/ -void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) { - /*gentity_t *ent; - vec3_t dir; - char *classname; - - // if the player was carrying cubes - if ( self->client->ps.generic1 ) { - if ( self->client->sess.sessionTeam == TEAM_DROIDS ) { - classname = "team_redobelisk"; - } - else { - classname = "team_blueobelisk"; - } - ent = G_Find(NULL, FOFS(classname), classname); - // if we found the destination obelisk - if ( ent ) { - // if the player was *very* close - VectorSubtract( self->client->ps.origin, ent->s.origin, dir ); - if ( VectorLength(dir) < 200 ) { - self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT; - if ( attacker->client ) { - attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT; - } - } - } - }*/ -} - - -/* -================== -player_die -================== -*/ -void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { - gentity_t *ent; - int anim; - int contents; - int killer; - int i; - char *killerName, *obit; - - if ( self->client->ps.pm_type == PM_DEAD ) { - return; - } - - if ( level.intermissiontime ) { - return; - } - - //TA: prolly dont need this - // check for an almost capture - //CheckAlmostCapture( self, attacker ); - // check for a player that almost brought in cubes - //CheckAlmostScored( self, attacker ); - - if (self->client && self->client->hook) - Weapon_HookFree(self->client->hook); - - self->client->ps.pm_type = PM_DEAD; - - if ( attacker ) { - killer = attacker->s.number; - if ( attacker->client ) { - killerName = attacker->client->pers.netname; - } else { - killerName = "<non-client>"; - } - } else { - killer = ENTITYNUM_WORLD; - killerName = "<world>"; - } - - if ( killer < 0 || killer >= MAX_CLIENTS ) { - killer = ENTITYNUM_WORLD; - killerName = "<world>"; - } - - if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) { - obit = "<bad obituary>"; - } else { - obit = modNames[ meansOfDeath ]; - } - - G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", - killer, self->s.number, meansOfDeath, killerName, - self->client->pers.netname, obit ); - - // broadcast the death event to everyone - ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY ); - ent->s.eventParm = meansOfDeath; - ent->s.otherEntityNum = self->s.number; - ent->s.otherEntityNum2 = killer; - ent->r.svFlags = SVF_BROADCAST; // send to everyone - - self->enemy = attacker; - - self->client->ps.persistant[PERS_KILLED]++; - - if (attacker && attacker->client) { - attacker->client->lastkilled_client = self->s.number; - if ( attacker == self || OnSameTeam (self, attacker ) ) { - AddScore( attacker, -1 ); - AddPoints( attacker, -10 ); - } else { - AddScore( attacker, 1 ); - AddPoints( attacker, CalculatePoints( self, attacker ) ); - - //TA: disable rewards - /*if( meansOfDeath == MOD_GAUNTLET ) { - attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++; - attacker->client->ps.persistant[PERS_REWARD] = REWARD_GAUNTLET; - attacker->client->ps.persistant[PERS_REWARD_COUNT]++; - - // add the sprite over the player's head - attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET ); - attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET; - attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME; - - // also play humiliation on target - self->client->ps.persistant[PERS_REWARD] = REWARD_GAUNTLET; - self->client->ps.persistant[PERS_REWARD_COUNT]++; - } - - // check for two kills in a short amount of time - // if this is close enough to the last kill, give a reward sound - if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) { - attacker->client->ps.persistant[PERS_REWARD_COUNT]++; - attacker->client->ps.persistant[PERS_REWARD] = REWARD_EXCELLENT; - attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++; - - // add the sprite over the player's head - attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET ); - attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT; - attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME; - }*/ - attacker->client->lastKillTime = level.time; - - } - } else { - AddScore( self, -1 ); - AddPoints( self, -10 ); - } - - // Add team bonuses - Team_FragBonuses(self, inflictor, attacker); - - // if client is in a nodrop area, don't drop anything (but return CTF flags!) - contents = trap_PointContents( self->r.currentOrigin, -1 ); - if ( !( contents & CONTENTS_NODROP ) ) - //TossClientItems( self ); - - Cmd_Score_f( self ); // show scores - // send updated scores to any clients that are following this one, - // or they would get stale scoreboards - for ( i = 0 ; i < level.maxclients ; i++ ) { - gclient_t *client; - - client = &level.clients[i]; - if ( client->pers.connected != CON_CONNECTED ) { - continue; - } - if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { - continue; - } - if ( client->sess.spectatorClient == self->s.number ) { - Cmd_Score_f( g_entities + i ); - } - } - - self->client->pers.pclass = 0; //TA: reset the classtype - - self->takedamage = qtrue; // can still be gibbed - - self->s.weapon = WP_NONE; - self->s.powerups = 0; - self->r.contents = CONTENTS_CORPSE; - - self->s.angles[0] = 0; - self->s.angles[2] = 0; - LookAtKiller (self, inflictor, attacker); - - VectorCopy( self->s.angles, self->client->ps.viewangles ); - - self->s.loopSound = 0; - - self->r.maxs[2] = -8; - - // don't allow respawn until the death anim is done - // g_forcerespawn may force spawning at some later time - self->client->respawnTime = level.time + 1700; - - // remove powerups - memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) ); - - // never gib in a nodrop - if ( self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer ) { - // gib death - GibEntity( self, killer ); - } else { - // normal death - static int i; - - switch ( i ) { - case 0: - anim = BOTH_DEATH1; - break; - case 1: - anim = BOTH_DEATH2; - break; - case 2: - default: - anim = BOTH_DEATH3; - break; - } - - // for the no-blood option, we need to prevent the health - // from going to gib level - if ( self->health <= GIB_HEALTH ) { - self->health = GIB_HEALTH+1; - } - - self->client->ps.legsAnim = - ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - self->client->ps.torsoAnim = - ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - - G_AddEvent( self, EV_DEATH1 + i, killer ); - - // the body can still be gibbed - self->die = body_die; - - // globally cycle through the different death animations - i = ( i + 1 ) % 3; - } - - trap_LinkEntity (self); -} - - -/* -================ -CheckArmor -================ -*/ -int CheckArmor (gentity_t *ent, int damage, int dflags) -{ - gclient_t *client; - int save; - int count; - - if (!damage) - return 0; - - client = ent->client; - - if (!client) - return 0; - - if (dflags & DAMAGE_NO_ARMOR) - return 0; - - // armor - count = client->ps.stats[STAT_ARMOR]; - save = ceil( damage * ARMOR_PROTECTION ); - if (save >= count) - save = count; - - if (!save) - return 0; - - client->ps.stats[STAT_ARMOR] -= save; - - return save; -} - - -/* -================ -RaySphereIntersections -================ -*/ -int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) { - float b, c, d, t; - - // | origin - (point + t * dir) | = radius - // a = dir[0]^2 + dir[1]^2 + dir[2]^2; - // b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2])); - // c = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2; - - // normalize dir so a = 1 - VectorNormalize(dir); - b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2])); - c = (point[0] - origin[0]) * (point[0] - origin[0]) + - (point[1] - origin[1]) * (point[1] - origin[1]) + - (point[2] - origin[2]) * (point[2] - origin[2]) - - radius * radius; - - d = b * b - 4 * c; - if (d > 0) { - t = (- b + sqrt(d)) / 2; - VectorMA(point, t, dir, intersections[0]); - t = (- b - sqrt(d)) / 2; - VectorMA(point, t, dir, intersections[1]); - return 2; - } - else if (d == 0) { - t = (- b ) / 2; - VectorMA(point, t, dir, intersections[0]); - return 1; - } - return 0; -} - - -/* -============ -T_Damage - -targ entity that is being damaged -inflictor entity that is causing the damage -attacker entity that caused the inflictor to damage targ - example: targ=monster, inflictor=rocket, attacker=player - -dir direction of the attack for knockback -point point at which the damage is being inflicted, used for headshots -damage amount of damage being inflicted -knockback force to be applied against targ as a result of the damage - -inflictor, attacker, dir, and point can be NULL for environmental effects - -dflags these flags are used to control how T_Damage works - DAMAGE_RADIUS damage was indirect (from a nearby explosion) - DAMAGE_NO_ARMOR armor does not protect from this damage - DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles - DAMAGE_NO_PROTECTION kills godmode, armor, everything -============ -*/ - -//TA: team is the team that is immune to this damage -void G_SelectiveDamage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, - vec3_t dir, vec3_t point, int damage, int dflags, int mod, int team ) -{ - if( targ->client && ( team != targ->client->pers.pteam ) ) - G_Damage( targ, inflictor, attacker, dir, point, damage, dflags, mod ); -} - -void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, - vec3_t dir, vec3_t point, int damage, int dflags, int mod ) { - gclient_t *client; - int take; - int save; - int asave; - int knockback; - int max; - - if (!targ->takedamage) { - return; - } - - // the intermission has allready been qualified for, so don't - // allow any extra scoring - if ( level.intermissionQueued ) { - return; - } - - if ( !inflictor ) { - inflictor = &g_entities[ENTITYNUM_WORLD]; - } - if ( !attacker ) { - attacker = &g_entities[ENTITYNUM_WORLD]; - } - - // shootable doors / buttons don't actually have any health - if ( targ->s.eType == ET_MOVER ) { - if ( targ->use && targ->moverState == MOVER_POS1 ) { - targ->use( targ, inflictor, attacker ); - } - return; - } - - //TA: handicaps.. WTF is all that about? If someone is shit they deserve to die. - // reduce damage by the attacker's handicap value - // unless they are rocket jumping - /*if ( attacker->client && attacker != targ ) { - damage = damage * attacker->client->ps.stats[STAT_MAX_HEALTH] / 100; - }*/ - - client = targ->client; - - if ( client ) { - if ( client->noclip ) { - return; - } - } - - if ( !dir ) { - dflags |= DAMAGE_NO_KNOCKBACK; - } else { - VectorNormalize(dir); - } - - knockback = damage; - if ( knockback > 200 ) { - knockback = 200; - } - if ( targ->flags & FL_NO_KNOCKBACK ) { - knockback = 0; - } - if ( dflags & DAMAGE_NO_KNOCKBACK ) { - knockback = 0; - } - - // figure momentum add, even if the damage won't be taken - if ( knockback && targ->client ) { - vec3_t kvel; - float mass; - - mass = 200; - - VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel); - VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity); - - // set the timer so that the other client can't cancel - // out the movement immediately - if ( !targ->client->ps.pm_time ) { - int t; - - t = knockback * 2; - if ( t < 50 ) { - t = 50; - } - if ( t > 200 ) { - t = 200; - } - targ->client->ps.pm_time = t; - targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - } - } - - // check for completely getting out of the damage - if ( !(dflags & DAMAGE_NO_PROTECTION) ) { - - // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target - // if the attacker was on the same team - if ( targ != attacker && OnSameTeam (targ, attacker) ) { - if ( !g_friendlyFire.integer ) { - return; - } - } - - // check for godmode - if ( targ->flags & FL_GODMODE ) { - return; - } - } - - // battlesuit protects from all radius damage (but takes knockback) - // and protects 50% against all damage - /*if ( client && client->ps.powerups[PW_BATTLESUIT] ) { - G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 ); - if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) { - return; - } - damage *= 0.5; - }*/ - - // add to the attacker's hit counter - if ( attacker->client && targ != attacker && targ->health > 0 - && targ->s.eType != ET_MISSILE - && targ->s.eType != ET_GENERAL) { - if ( OnSameTeam( targ, attacker ) ) { - attacker->client->ps.persistant[PERS_HITS] --; - } else { - attacker->client->ps.persistant[PERS_HITS] ++; - } - } - - // always give half damage if hurting self - // calculated after knockback, so rocket jumping works - if ( targ == attacker) { - damage *= 0.5; - } - - if ( damage < 1 ) { - damage = 1; - } - take = damage; - save = 0; - - // save some from armor - asave = CheckArmor (targ, take, dflags); - take -= asave; - - if ( g_debugDamage.integer ) { - G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, - targ->health, take, asave ); - } - - // add to the damage inflicted on a player this frame - // the total will be turned into screen blends and view angle kicks - // at the end of the frame - if ( client ) { - if ( attacker ) { - client->ps.persistant[PERS_ATTACKER] = attacker->s.number; - } else { - client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD; - } - client->damage_armor += asave; - client->damage_blood += take; - client->damage_knockback += knockback; - if ( dir ) { - VectorCopy ( dir, client->damage_from ); - client->damage_fromWorld = qfalse; - } else { - VectorCopy ( targ->r.currentOrigin, client->damage_from ); - client->damage_fromWorld = qtrue; - } - } - - // See if it's the player hurting the emeny flag carrier - if( g_gametype.integer == GT_CTF) { - Team_CheckHurtCarrier(targ, attacker); - } - - if (targ->client) { - // set the last client who damaged the target - targ->client->lasthurt_client = attacker->s.number; - targ->client->lasthurt_mod = mod; - } - - // do the damage - if (take) { - targ->health = targ->health - take; - if ( targ->client ) { - targ->client->ps.stats[STAT_HEALTH] = targ->health; - } - - if ( targ->health <= 0 ) { - if ( client ) - targ->flags |= FL_NO_KNOCKBACK; - - if (targ->health < -999) - targ->health = -999; - - targ->enemy = attacker; - targ->die (targ, inflictor, attacker, take, mod); - return; - } else if ( targ->pain ) { - targ->pain (targ, attacker, take); - } - } - -} - - -/* -============ -CanDamage - -Returns qtrue if the inflictor can directly damage the target. Used for -explosions and melee attacks. -============ -*/ -qboolean CanDamage (gentity_t *targ, vec3_t origin) { - vec3_t dest; - trace_t tr; - vec3_t midpoint; - - // use the midpoint of the bounds instead of the origin, because - // bmodels may have their origin is 0,0,0 - VectorAdd (targ->r.absmin, targ->r.absmax, midpoint); - VectorScale (midpoint, 0.5, midpoint); - - VectorCopy (midpoint, dest); - trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); - if (tr.fraction == 1.0 || tr.entityNum == targ->s.number) - return qtrue; - - // this should probably check in the plane of projection, - // rather than in world coordinate, and also include Z - VectorCopy (midpoint, dest); - dest[0] += 15.0; - dest[1] += 15.0; - trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); - if (tr.fraction == 1.0) - return qtrue; - - VectorCopy (midpoint, dest); - dest[0] += 15.0; - dest[1] -= 15.0; - trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); - if (tr.fraction == 1.0) - return qtrue; - - VectorCopy (midpoint, dest); - dest[0] -= 15.0; - dest[1] += 15.0; - trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); - if (tr.fraction == 1.0) - return qtrue; - - VectorCopy (midpoint, dest); - dest[0] -= 15.0; - dest[1] -= 15.0; - trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); - if (tr.fraction == 1.0) - return qtrue; - - - return qfalse; -} - - -//TA: -/* -============ -G_RadiusDamage -============ -*/ -qboolean G_SelectiveRadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius, - gentity_t *ignore, int mod, int team ) { - float points, dist; - gentity_t *ent; - int entityList[MAX_GENTITIES]; - int numListedEntities; - vec3_t mins, maxs; - vec3_t v; - vec3_t dir; - int i, e; - qboolean hitClient = qfalse; - - if ( radius < 1 ) { - radius = 1; - } - - for ( i = 0 ; i < 3 ; i++ ) { - mins[i] = origin[i] - radius; - maxs[i] = origin[i] + radius; - } - - numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - - for ( e = 0 ; e < numListedEntities ; e++ ) { - ent = &g_entities[entityList[ e ]]; - - if (ent == ignore) - continue; - if (!ent->takedamage) - continue; - - // find the distance from the edge of the bounding box - for ( i = 0 ; i < 3 ; i++ ) { - if ( origin[i] < ent->r.absmin[i] ) { - v[i] = ent->r.absmin[i] - origin[i]; - } else if ( origin[i] > ent->r.absmax[i] ) { - v[i] = origin[i] - ent->r.absmax[i]; - } else { - v[i] = 0; - } - } - - dist = VectorLength( v ); - if ( dist >= radius ) { - continue; - } - - points = damage * ( 1.0 - dist / radius ); - - if( CanDamage (ent, origin) ) { - if( LogAccuracyHit( ent, attacker ) ) { - hitClient = qtrue; - } - VectorSubtract (ent->r.currentOrigin, origin, dir); - // push the center of mass higher than the origin so players - // get knocked into the air more - dir[2] += 24; - G_SelectiveDamage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod, team ); - } - } - - return hitClient; -} - - -/* -============ -G_RadiusDamage -============ -*/ -qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius, - gentity_t *ignore, int mod) { - float points, dist; - gentity_t *ent; - int entityList[MAX_GENTITIES]; - int numListedEntities; - vec3_t mins, maxs; - vec3_t v; - vec3_t dir; - int i, e; - qboolean hitClient = qfalse; - - if ( radius < 1 ) { - radius = 1; - } - - for ( i = 0 ; i < 3 ; i++ ) { - mins[i] = origin[i] - radius; - maxs[i] = origin[i] + radius; - } - - numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - - for ( e = 0 ; e < numListedEntities ; e++ ) { - ent = &g_entities[entityList[ e ]]; - - if (ent == ignore) - continue; - if (!ent->takedamage) - continue; - - // find the distance from the edge of the bounding box - for ( i = 0 ; i < 3 ; i++ ) { - if ( origin[i] < ent->r.absmin[i] ) { - v[i] = ent->r.absmin[i] - origin[i]; - } else if ( origin[i] > ent->r.absmax[i] ) { - v[i] = origin[i] - ent->r.absmax[i]; - } else { - v[i] = 0; - } - } - - dist = VectorLength( v ); - if ( dist >= radius ) { - continue; - } - - points = damage * ( 1.0 - dist / radius ); - - if( CanDamage (ent, origin) ) { - if( LogAccuracyHit( ent, attacker ) ) { - hitClient = qtrue; - } - VectorSubtract (ent->r.currentOrigin, origin, dir); - // push the center of mass higher than the origin so players - // get knocked into the air more - dir[2] += 24; - G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod); - } - } - - return hitClient; -} |