コード例 #1
0
ファイル: g_combat.c プロジェクト: Kaperstone/warsow
/*
* G_Killed
*/
void G_Killed( edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t point, int mod )
{
	if( targ->health < -999 )
		targ->health = -999;

	if( targ->deadflag == DEAD_DEAD )
		return;

	targ->deadflag = DEAD_DEAD;
	targ->enemy = attacker;

	if( targ->r.client )
	{
		if( attacker && targ != attacker )
		{
			if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
				attacker->snap.teamkill = qtrue;
			else
				attacker->snap.kill = qtrue;
		}

		// count stats
		if( GS_MatchState() == MATCH_STATE_PLAYTIME )
		{
			targ->r.client->level.stats.deaths++;
			teamlist[targ->s.team].stats.deaths++;

			if( !attacker || !attacker->r.client || attacker == targ || attacker == world )
			{
				targ->r.client->level.stats.suicides++;
				teamlist[targ->s.team].stats.suicides++;
			}
			else
			{
				if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
				{
					attacker->r.client->level.stats.teamfrags++;
					teamlist[attacker->s.team].stats.teamfrags++;
				}
				else
				{
					attacker->r.client->level.stats.frags++;
					teamlist[attacker->s.team].stats.frags++;
					G_AwardPlayerKilled( targ, inflictor, attacker, mod );
				}
			}
		}
	}

	G_Gametype_ScoreEvent( attacker ? attacker->r.client : NULL, "kill", va( "%i %i %i", targ->s.number, ( inflictor == world ) ? -1 : ENTNUM( inflictor ), ENTNUM( attacker ) ) );

	G_CallDie( targ, inflictor, attacker, damage, point );
}
コード例 #2
0
void G_Gametype_GENERIC_PlayerKilled( edict_t *targ, edict_t *attacker, edict_t *inflictor )
{
	if( !attacker || GS_MatchState() != MATCH_STATE_PLAYTIME || ( targ->r.svflags & SVF_CORPSE ) )
		return;

	if( !attacker->r.client || attacker == targ || attacker == world )
		teamlist[targ->s.team].stats.score--;
	else
	{
		if( GS_InvidualGameType() )
			teamlist[attacker->s.team].stats.score = attacker->r.client->level.stats.score;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
			teamlist[attacker->s.team].stats.score--;
		else
			teamlist[attacker->s.team].stats.score++;
	}

	// drop items
	if( targ->r.client && !( G_PointContents( targ->s.origin ) & CONTENTS_NODROP ) )
	{
		// drop the weapon
		if ( targ->r.client->ps.stats[STAT_WEAPON] > WEAP_GUNBLADE )
		{
			gsitem_t *weaponItem = GS_FindItemByTag( targ->r.client->ps.stats[STAT_WEAPON] );
			if( weaponItem )
			{
				edict_t *drop = Drop_Item( targ, weaponItem );
				if( drop )
				{
					drop->count = targ->r.client->ps.inventory[ weaponItem->weakammo_tag ];
					targ->r.client->ps.inventory[ weaponItem->weakammo_tag ] = 0;
				}
			}
		}

		// drop ammo pack (won't drop anything if player doesn't have any strong ammo)
		Drop_Item( targ, GS_FindItemByTag( AMMO_PACK ) );
	}
}
コード例 #3
0
ファイル: g_weapon.c プロジェクト: Kaperstone/warsow
/*
* 
* - We will consider direct impacts as splash when the player is on the ground and the hit very close to the ground
*/
int G_Projectile_HitStyle( edict_t *projectile, edict_t *target )
{
	trace_t trace;
	vec3_t end;
	qboolean atGround = qfalse;
	edict_t *attacker;
#define AIRHIT_MINHEIGHT 64

	// don't hurt owner for the first second
	if( target == projectile->r.owner && target != world )
	{
		if( !g_projectile_touch_owner->integer ||
			( g_projectile_touch_owner->integer && projectile->timeStamp + 1000 > level.time ) )
			return PROJECTILE_TOUCH_NOT;
	}

	if( !target->takedamage || ISBRUSHMODEL( target->s.modelindex ) )
		return PROJECTILE_TOUCH_DIRECTHIT;

	if( target->waterlevel > 1 )
		return PROJECTILE_TOUCH_DIRECTHIT; // water hits are direct but don't count for awards

	attacker = ( projectile->r.owner && projectile->r.owner->r.client ) ? projectile->r.owner : NULL;

	// see if the target is at ground or a less than a step of height
	if( target->groundentity )
		atGround = qtrue;
	else
	{
		VectorCopy( target->s.origin, end );
		end[2] -= STEPSIZE;

		G_Trace4D( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_DEADSOLID, 0 );
		if( ( trace.ent != -1 || trace.startsolid ) && ISWALKABLEPLANE( &trace.plane ) )
			atGround = qtrue;
	}

	if( atGround )
	{
		// when the player is at ground we will consider a direct hit only when
		// the hit is 16 units above the feet
		if( projectile->s.origin[2] <= 16 + target->s.origin[2] + target->r.mins[2] )
			return PROJECTILE_TOUCH_DIRECTSPLASH;
	}
	else
	{
		// it's direct hit, but let's see if it's airhit
		VectorCopy( target->s.origin, end );
		end[2] -= AIRHIT_MINHEIGHT;

		G_Trace4D( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_DEADSOLID, 0 );
		if( ( trace.ent != -1 || trace.startsolid ) && ISWALKABLEPLANE( &trace.plane ) )
		{
			// add directhit and airhit to awards counter
			if( attacker && !GS_IsTeamDamage( &attacker->s, &target->s ) && G_ModToAmmo( projectile->style ) != AMMO_NONE )
			{
				projectile->r.owner->r.client->level.stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;
				teamlist[projectile->r.owner->s.team].stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;

				projectile->r.owner->r.client->level.stats.accuracy_hits_air[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;
				teamlist[projectile->r.owner->s.team].stats.accuracy_hits_air[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;
			}

			return PROJECTILE_TOUCH_DIRECTAIRHIT;
		}
	}

	// add directhit to awards counter
	if( attacker && !GS_IsTeamDamage( &attacker->s, &target->s ) && G_ModToAmmo( projectile->style ) != AMMO_NONE )
	{
		projectile->r.owner->r.client->level.stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;
		teamlist[projectile->r.owner->s.team].stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++;
	}

	return PROJECTILE_TOUCH_DIRECTHIT;

#undef AIRHIT_MINHEIGHT
}
コード例 #4
0
ファイル: g_chase.cpp プロジェクト: MGXRace/racesow
/*
* G_Chase_FindFollowPOV
*/
static int G_Chase_FindFollowPOV( edict_t *ent )
{
	int i, j;
	int quad, warshell, regen, scorelead;
	int maxteam;
	int flags[GS_MAX_TEAMS];
	int newctfpov, newpoweruppov;
	int score_best;
	int newpov = -1;
	edict_t *target;
	static int ctfpov = -1, poweruppov = -1;
	static unsigned int flagswitchTime = 0;
	static unsigned int pwupswitchTime = 0;
#define CARRIERSWITCHDELAY 8000

	if( !ent->r.client || !ent->r.client->resp.chase.active || !ent->r.client->resp.chase.followmode )
		return newpov;

	// follow killer, with a small delay
	if( ( ent->r.client->resp.chase.followmode & 8 ) ) {
		edict_t *targ;

		targ = &game.edicts[ent->r.client->resp.chase.target];
		if( G_IsDead( targ ) && targ->deathTimeStamp + 400 < level.time ) {
			edict_t *attacker = targ->r.client->teamstate.last_killer;

			// ignore world and team kills
			if( attacker && attacker->r.client && !GS_IsTeamDamage( &targ->s, &attacker->s ) ) {
				newpov = ENTNUM( attacker );
			}
		}

		return newpov;
	}

	// find what players have what
	score_best = 999999999; // racesow: changed from -999999999 to find lowest score (fastest time)
	if( level.gametype.inverseScore )
		score_best *= -1;
	quad = warshell = regen = scorelead = -1;
	memset( flags, -1, sizeof( flags ) );
	newctfpov = newpoweruppov = -1;
	maxteam = 0;

	for( i = 1; PLAYERNUM( (game.edicts+i) ) < gs.maxclients; i++ )
	{
		target = game.edicts + i;

		if( !target->r.inuse || trap_GetClientState( PLAYERNUM( target ) ) < CS_SPAWNED )
		{
			// check if old targets are still valid
			if( ctfpov == ENTNUM( target ) )
				ctfpov = -1;
			if( poweruppov == ENTNUM( target ) )
				poweruppov = -1;
			continue;
		}
		if( target->s.team <= 0 || target->s.team >= (int)(sizeof( flags ) / sizeof( flags[0] )) )
			continue;
		if( ent->r.client->resp.chase.teamonly && ent->s.team != target->s.team )
			continue;

		if( target->s.effects & EF_QUAD )
			quad = ENTNUM( target );
		if( target->s.effects & EF_SHELL )
			warshell = ENTNUM( target );
		if( target->s.effects & EF_REGEN )
			regen = ENTNUM( target );

		if( target->s.team && (target->s.effects & EF_CARRIER) )
		{
			if( target->s.team > maxteam )
				maxteam = target->s.team;
			flags[target->s.team-1] = ENTNUM( target );
		}

		// find the scoring leader
		if( ( !level.gametype.inverseScore && target->r.client->ps.stats[STAT_SCORE] // racesow: find lowest non-zero score (fastest time)
				&& target->r.client->ps.stats[STAT_SCORE] < score_best )
			|| ( level.gametype.inverseScore && target->r.client->ps.stats[STAT_SCORE] // racesow: find highest non-zero score (slowest time)
				&& target->r.client->ps.stats[STAT_SCORE] > score_best )
			)
		{
			score_best = target->r.client->ps.stats[STAT_SCORE];
			scorelead = ENTNUM( target );
		}
	}

	// do some categorization

	for( i = 0; i < maxteam; i++ )
	{
		if( flags[i] == -1 )
			continue;

		// default new ctfpov to the first flag carrier
		if( newctfpov == -1 )
			newctfpov = flags[i];
		else
			break;
	}

	// do we have more than one flag carrier?
	if( i < maxteam )
	{
		// default to old ctfpov
		if( ctfpov >= 0 )
			newctfpov = ctfpov;
		if( ctfpov < 0 || level.time > flagswitchTime )
		{
			// alternate between flag carriers
			for( i = 0; i < maxteam; i++ )
			{
				if( flags[i] != ctfpov )
					continue;

				for( j = 0; j < maxteam-1; j++ )
				{
					if( flags[(i+j+1)%maxteam] != -1 )
					{
						newctfpov = flags[(i+j+1)%maxteam];
						break;
					}
				}
				break;
			}
		}

		if( newctfpov != ctfpov )
		{
			ctfpov = newctfpov;
			flagswitchTime = level.time + CARRIERSWITCHDELAY;
		}
	}
	else
	{
		ctfpov = newctfpov;
		flagswitchTime = 0;
	}

	if( quad != -1 && warshell != -1 && quad != warshell )
	{
		// default to old powerup
		if( poweruppov >= 0 )
			newpoweruppov = poweruppov;
		if( poweruppov < 0 || level.time > pwupswitchTime )
		{
			if( poweruppov == quad )
				newpoweruppov = warshell;
			else if( poweruppov == warshell )
				newpoweruppov = quad;
			else 
				newpoweruppov = ( rand() & 1 ) ? quad : warshell;
		}

		if( poweruppov != newpoweruppov )
		{
			poweruppov = newpoweruppov;
			pwupswitchTime = level.time + CARRIERSWITCHDELAY;
		}
	}
	else
	{
		if( quad != -1 )
			newpoweruppov = quad;
		else if( warshell != -1 )
			newpoweruppov = warshell;
		else if( regen != -1 )
			newpoweruppov = regen;

		poweruppov = newpoweruppov;
		pwupswitchTime = 0;
	}

	// so, we got all, select what we prefer to show
	if( ctfpov != -1 && ( ent->r.client->resp.chase.followmode & 4 ) )
		newpov = ctfpov;
	else if( poweruppov != -1 && ( ent->r.client->resp.chase.followmode & 2 ) )
		newpov = poweruppov;
	else if( scorelead != -1 && ( ent->r.client->resp.chase.followmode & 1 ) )
		newpov = scorelead;

	return newpov;
#undef CARRIERSWITCHDELAY
}
コード例 #5
0
ファイル: p_hud.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_SetClientStats
*/
void G_SetClientStats( edict_t *ent )
{
	gclient_t *client = ent->r.client;
	int team, i;

	if( ent->r.client->resp.chase.active )  // in chasecam it copies the other player stats
		return;

	//
	// layouts
	//
	client->ps.stats[STAT_LAYOUTS] = 0;

	// don't force scoreboard when dead during timeout
	if( ent->r.client->level.showscores || GS_MatchState() >= MATCH_STATE_POSTMATCH )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_SCOREBOARD;
	if( GS_TeamBasedGametype() && !GS_InvidualGameType() )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_TEAMTAB;
	if( GS_HasChallengers() && ent->r.client->queueTimeStamp )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_CHALLENGER;
	if( GS_MatchState() <= MATCH_STATE_WARMUP && level.ready[PLAYERNUM( ent )] )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_READY;
	if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_INSTANT )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_INSTANTRESPAWN;

	//
	// team
	//
	client->ps.stats[STAT_TEAM] = client->ps.stats[STAT_REALTEAM] = ent->s.team;

	//
	// health
	//
	if( ent->s.team == TEAM_SPECTATOR )
		client->ps.stats[STAT_HEALTH] = STAT_NOTSET; // no health for spectator
	else
		client->ps.stats[STAT_HEALTH] = HEALTH_TO_INT( ent->health );
	client->r.frags = client->ps.stats[STAT_SCORE];

	//
	// armor
	//
	if( GS_Instagib() )
	{
		if( g_instashield->integer )
			client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( 100.0f * ( client->resp.instashieldCharge / INSTA_SHIELD_MAX ) );
		else
			client->ps.stats[STAT_ARMOR] = 0;
	}
	else
		client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( client->resp.armor );

	//
	// pickup message
	//
	if( level.time > client->resp.pickup_msg_time )
	{
		client->ps.stats[STAT_PICKUP_ITEM] = 0;
	}

	//
	// frags
	//
	if( ent->s.team == TEAM_SPECTATOR )
	{
		client->ps.stats[STAT_SCORE] = STAT_NOTSET; // no frags for spectators
	}
	else
	{
		client->ps.stats[STAT_SCORE] = ent->r.client->level.stats.score;
	}

	//
	// Team scores
	//
	if( GS_TeamBasedGametype() )
	{
		// team based
		i = 0;
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = teamlist[team].stats.score;
			i++;
		}
		// mark the rest as not set
		for(; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET;
			i++;
		}
	}
	else
	{
		// not team based
		i = 0;
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET;
			i++;
		}
	}

	// spawn system
	client->ps.stats[STAT_NEXT_RESPAWN] = ceil( G_SpawnQueue_NextRespawnTime( client->team ) * 0.001f );

	// pointed player
	client->ps.stats[STAT_POINTED_TEAMPLAYER] = 0;
	client->ps.stats[STAT_POINTED_PLAYER] = G_FindPointedPlayer( ent );
	if( client->ps.stats[STAT_POINTED_PLAYER] && GS_TeamBasedGametype() )
	{
		edict_t	*e = &game.edicts[client->ps.stats[STAT_POINTED_PLAYER]];
		if( e->s.team == ent->s.team )
		{
			int pointedhealth = HEALTH_TO_INT( e->health );
			int pointedarmor = 0;
			int available_bits = 0;
			bool mega = false;

			if( pointedhealth < 0 ) pointedhealth = 0;
			if( pointedhealth > 100 )
			{
				pointedhealth -= 100;
				mega = true;
				if( pointedhealth > 100 )
					pointedhealth = 100;
			}
			pointedhealth /= 3.2;

			if( GS_Armor_TagForCount( e->r.client->resp.armor ) )
			{
				pointedarmor = ARMOR_TO_INT( e->r.client->resp.armor );
			}
			if( pointedarmor > 150 )
			{
				pointedarmor = 150;
			}
			pointedarmor /= 5;

			client->ps.stats[STAT_POINTED_TEAMPLAYER] = ( ( pointedhealth &0x1F )|( pointedarmor&0x3F )<<6|( available_bits&0xF )<<12 );
			if( mega )
			{
				client->ps.stats[STAT_POINTED_TEAMPLAYER] |= 0x20;
			}
		}
	}

	// last killer. ignore world and team kills
	if( client->teamstate.last_killer )
	{
		edict_t *targ = ent, *attacker = client->teamstate.last_killer;
		client->ps.stats[STAT_LAST_KILLER] = (attacker->r.client && !GS_IsTeamDamage( &targ->s, &attacker->s ) ? 
			ENTNUM( attacker ) : 0);
	}
	else
	{
		client->ps.stats[STAT_LAST_KILLER] = 0;
	}
}
コード例 #6
0
ファイル: g_combat.c プロジェクト: Kaperstone/warsow
/*
* G_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=enemy, inflictor=rocket, attacker=player
*
* dir			direction of the attack
* point		point at which the damage is being inflicted
* normal		normal vector from that point
* damage		amount of damage being inflicted
* knockback	force to be applied against targ as a result of the damage
*
* dflags		these flags are used to control how T_Damage works
*/
void G_Damage( edict_t *targ, edict_t *inflictor, edict_t *attacker, const vec3_t pushdir, const vec3_t dmgdir, const vec3_t point, float damage, float knockback, float stun, int dflags, int mod )
{
	gclient_t *client;
	float take;
	float save;
	float asave;
	qboolean statDmg;

	if( !targ || !targ->takedamage )
		return;

	if( !attacker )
	{
		attacker = world;
		mod = MOD_TRIGGER_HURT;
	}

	meansOfDeath = mod;

	client = targ->r.client;

	// Cgg - race mode: players don't interact with one another
	if( GS_RaceGametype() )
	{
		if( attacker->r.client && targ->r.client && attacker != targ )
			return;
	}

	// push
	if( !( dflags & DAMAGE_NO_KNOCKBACK ) )
		G_KnockBackPush( targ, attacker, pushdir, knockback, dflags );

	// stun
	if( g_allow_stun->integer && !( dflags & (DAMAGE_NO_STUN|FL_GODMODE) )
		&& (int)stun > 0 && targ->r.client && targ->r.client->resp.takeStun &&
		!GS_IsTeamDamage( &targ->s, &attacker->s ) && ( targ != attacker ) )
	{
		if( dflags & DAMAGE_STUN_CLAMP )
		{
			if( targ->r.client->ps.pmove.stats[PM_STAT_STUN] < (int)stun )
				targ->r.client->ps.pmove.stats[PM_STAT_STUN] = (int)stun;
		}
		else
			targ->r.client->ps.pmove.stats[PM_STAT_STUN] += (int)stun;

		clamp( targ->r.client->ps.pmove.stats[PM_STAT_STUN], 0, MAX_STUN_TIME );
	}

	// dont count self-damage cause it just adds the same to both stats
	statDmg = ( attacker != targ ) && ( mod != MOD_TELEFRAG );

	// apply handicap on the damage given
	if( statDmg && attacker->r.client && !GS_Instagib() )
	{
		// handicap is a percentage value
		if( attacker->r.client->handicap != 0 )
			damage *= 1.0 - (attacker->r.client->handicap * 0.01f);
	}

	take = damage;
	save = 0;

	// check for cases where damage is protected
	if( !( dflags & DAMAGE_NO_PROTECTION ) )
	{
		// check for godmode
		if( targ->flags & FL_GODMODE )
		{
			take = 0;
			save = damage;
		}
		// never damage in timeout
		else if( GS_MatchPaused() )
		{
			take = save = 0;
		}
		// ca has self splash damage disabled
		else if( ( dflags & DAMAGE_RADIUS ) && attacker == targ && !GS_SelfDamage() )
		{
			take = save = 0;
		}
		// don't get damage from players in race
		else if( ( GS_RaceGametype() ) && attacker->r.client && targ->r.client &&
			( attacker->r.client != targ->r.client ) )
		{
			take = save = 0;
		}
		// team damage avoidance
		else if( GS_IsTeamDamage( &targ->s, &attacker->s ) && !G_Gametype_CanTeamDamage( dflags ) )
		{
			take = save = 0;
		}
		// apply warShell powerup protection
		else if( targ->r.client && targ->r.client->ps.inventory[POWERUP_SHELL] > 0 )
		{
			// warshell offers full protection in instagib
			if( GS_Instagib() )
			{
				take = 0;
				save = damage;
			}
			else
			{
				take = ( damage * 0.25f );
				save = damage - take;
			}
			// todo : add protection sound
		}
	}

	asave = G_CheckArmor( targ, take, dflags );
	take -= asave;

	//treat cheat/powerup savings the same as armor
	asave += save;

	// APPLY THE DAMAGES

	if( !take && !asave )
		return;

	// do the damage
	if( take <= 0 )
		return;

	// adding damage given/received to stats
	if( statDmg && attacker->r.client && !targ->deadflag && targ->movetype != MOVETYPE_PUSH && targ->s.type != ET_CORPSE )
	{
		attacker->r.client->level.stats.total_damage_given += take + asave;
		teamlist[attacker->s.team].stats.total_damage_given += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			attacker->r.client->level.stats.total_teamdamage_given += take + asave;
			teamlist[attacker->s.team].stats.total_teamdamage_given += take + asave;
		}
	}

	G_Gametype_ScoreEvent( attacker->r.client, "dmg", va( "%i %f %i", targ->s.number, damage, attacker->s.number ) );

	if( statDmg && client )
	{
		client->level.stats.total_damage_received += take + asave;
		teamlist[targ->s.team].stats.total_damage_received += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			client->level.stats.total_teamdamage_received += take + asave;
			teamlist[targ->s.team].stats.total_teamdamage_received += take + asave;
		}
	}

	// accumulate received damage for snapshot effects
	{
		vec3_t dorigin;

		if( inflictor == world && mod == MOD_FALLING ) // it's fall damage
			targ->snap.damage_fall += take + save;

		if( point[0] != 0.0f || point[1] != 0.0f || point[2] != 0.0f )
			VectorCopy( point, dorigin );
		else
			VectorSet( dorigin,
			targ->s.origin[0],
			targ->s.origin[1],
			targ->s.origin[2] + targ->viewheight );

		G_BlendFrameDamage( targ, take, &targ->snap.damage_taken, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );
		G_BlendFrameDamage( targ, save, &targ->snap.damage_saved, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );

		if( targ->r.client )
		{
			if( mod != MOD_FALLING && mod != MOD_TELEFRAG && mod != MOD_SUICIDE )
			{
				if( inflictor == world || attacker == world )
				{
					// for world inflicted damage use always 'frontal'
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, NULL );
				}
				else if( dflags & DAMAGE_RADIUS )
				{
					// for splash hits the direction is from the inflictor origin
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, pushdir );
				}
				else
				{	// for direct hits the direction is the projectile direction
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, dmgdir );
				}
			}
		}
	}

	targ->health = targ->health - take;

	// add damage done to stats
	if( !GS_IsTeamDamage( &targ->s, &attacker->s ) && statDmg && G_ModToAmmo( mod ) != AMMO_NONE && client && attacker->r.client )
	{
		attacker->r.client->level.stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		attacker->r.client->level.stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;
		teamlist[attacker->s.team].stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		teamlist[attacker->s.team].stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;

		G_AwardPlayerHit( targ, attacker, mod );
	}

	// accumulate given damage for hit sounds
	if( ( take || asave ) && targ != attacker && client && !targ->deadflag )
	{
		if( attacker )
		{
			if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
				attacker->snap.damageteam_given += take + asave; // we want to know how good our hit was, so saved also matters
			else
				attacker->snap.damage_given += take + asave;
		}
	}

	if( G_IsDead( targ ) )
	{
		if( client )
			targ->flags |= FL_NO_KNOCKBACK;
		G_Killed( targ, inflictor, attacker, HEALTH_TO_INT( take ), point, mod );
	}
	else 
	{
		G_CallPain( targ, attacker, knockback, take );
	}
}