Exemple #1
0
void G_AwardPlayerKilled( edict_t *self, edict_t *inflictor, edict_t *attacker, int mod )
{
    trace_t trace;
    score_stats_t *stats;
    loggedFrag_t *lfrag;

    if( self->r.svflags & SVF_CORPSE )
        return;

    if( !attacker->r.client )
        return;

    if( !self->r.client )
        return;

    if( attacker == self )
        return;

    if( attacker->s.team == self->s.team && attacker->s.team > TEAM_PLAYERS )
        return;

    if( mod == MOD_ROCKET_W || mod == MOD_ROCKET_S )
    {
        // direct hit
        attacker->r.client->resp.awardInfo.directrocket_count++;
        if( attacker->r.client->resp.awardInfo.directrocket_count == DIRECTROCKET_FOR_AWARD )
        {
            attacker->r.client->resp.awardInfo.directrocket_count = 0;
            attacker->r.client->resp.awardInfo.directrocket_award++;
            G_PlayerAward( attacker, S_COLOR_BLUE "Direct Rocket Hit!" );
        }
        // Midair
        if( self->groundentity == NULL && !self->waterlevel )
        {
            // check for height to the ground
            G_Trace( &trace, self->s.origin, self->r.mins, self->r.maxs, tv( self->s.origin[0], self->s.origin[1], self->s.origin[2] - 64 ), self, MASK_SOLID );
            if( trace.fraction == 1.0f )
            {
                attacker->r.client->resp.awardInfo.rl_midair_award++;
                G_PlayerAward( attacker, S_COLOR_BLUE "Air Rocket!" );
            }
        }
    }
    if( mod == MOD_GRENADE_W || mod == MOD_GRENADE_S )
    {
        // direct hit
        attacker->r.client->resp.awardInfo.directgrenade_count++;
        if( attacker->r.client->resp.awardInfo.directgrenade_count == DIRECTGRENADE_FOR_AWARD )
        {
            attacker->r.client->resp.awardInfo.directgrenade_count = 0;
            attacker->r.client->resp.awardInfo.directgrenade_award++;
            G_PlayerAward( attacker, S_COLOR_BLUE "Direct Grenade Hit!" );
        }

        // Midair
        if( self->groundentity == NULL && !self->waterlevel )
        {
            // check for height to the ground
            G_Trace( &trace, self->s.origin, self->r.mins, self->r.maxs, tv( self->s.origin[0], self->s.origin[1], self->s.origin[2] - 64 ), self, MASK_SOLID );
            if( trace.fraction == 1.0f )
            {
                attacker->r.client->resp.awardInfo.gl_midair_award++;
                G_PlayerAward( attacker, S_COLOR_BLUE "Air Grenade!" );
            }
        }
    }

    // Multikill
    if( game.serverTime - attacker->r.client->resp.awardInfo.multifrag_timer < MULTIKILL_INTERVAL )
        attacker->r.client->resp.awardInfo.multifrag_count++;
    else
        attacker->r.client->resp.awardInfo.multifrag_count = 1;

    attacker->r.client->resp.awardInfo.multifrag_timer = game.serverTime;

    if( attacker->r.client->resp.awardInfo.multifrag_count > 1 )
    {
        char s[MAX_CONFIGSTRING_CHARS];

        s[0] = 0;

        switch( attacker->r.client->resp.awardInfo.multifrag_count )
        {
        case 0:
        case 1:
            break;
        case 2:
            Q_strncpyz( s, S_COLOR_GREEN "Double Frag!", sizeof( s ) );
            break;
        case 3:
            Q_strncpyz( s, S_COLOR_GREEN "Triple Frag!", sizeof( s ) );
            break;
        case 4:
            Q_strncpyz( s, S_COLOR_GREEN "Quadruple Frag!", sizeof( s ) );
            break;
        default:
            Q_snprintfz( s, sizeof( s ), S_COLOR_GREEN "Extermination! %i in a row!", attacker->r.client->resp.awardInfo.multifrag_count );
            break;
        }

        G_PlayerAward( attacker, s );
    }

    // Sprees
    attacker->r.client->resp.awardInfo.frag_count++;

    if( attacker->r.client->resp.awardInfo.frag_count &&
            ( attacker->r.client->resp.awardInfo.frag_count % 5 == 0 ) )
    {
        char s[MAX_CONFIGSTRING_CHARS];

        s[0] = 0;

        switch( (int)( attacker->r.client->resp.awardInfo.frag_count / 5 ) )
        {
        case 1:
            Q_strncpyz( s, S_COLOR_YELLOW "On Fire!", sizeof( s ) );
            G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " is On Fire!\n", attacker->r.client->netname );
            break;
        case 2:
            Q_strncpyz( s, S_COLOR_YELLOW "Raging!", sizeof( s ) );
            G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " is Raging!\n", attacker->r.client->netname );
            break;
        case 3:
            Q_strncpyz( s, S_COLOR_YELLOW "Fraglord!", sizeof( s ) );
            G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " is the Fraglord!\n", attacker->r.client->netname );
            break;
        case 4:
            Q_strncpyz( s, S_COLOR_YELLOW "Extermination!", sizeof( s ) );
            G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " is Exterminating!\n", attacker->r.client->netname );
            break;
        default:
            Q_strncpyz( s, S_COLOR_YELLOW "God Mode!", sizeof( s ) );
            G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " is in God Mode!\n", attacker->r.client->netname );
            break;
        }

        G_PlayerAward( attacker, s );
    }

    // ch : weapon specific frags
    if ( G_ModToAmmo( mod ) != AMMO_NONE )
        attacker->r.client->level.stats.accuracy_frags[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;

    if( GS_MatchState() == MATCH_STATE_PLAYTIME /* && !strcmp( "duel", gs.gametypeName ) */)
    {
        // ch : frag log
        stats = &attacker->r.client->level.stats;
        if( !stats->fragAllocator )
            stats->fragAllocator = LinearAllocator( sizeof( loggedFrag_t ), 0, _G_LevelMalloc, _G_LevelFree );

        lfrag = LA_Alloc( stats->fragAllocator );
        lfrag->mm_attacker = attacker->r.client->mm_session;
        lfrag->mm_victim = self->r.client->mm_session;
        lfrag->weapon = G_ModToAmmo( mod ) - AMMO_GUNBLADE;
        lfrag->time = ( game.serverTime - GS_MatchStartTime() ) / 1000;
    }
}
Exemple #2
0
/*
* 
* - 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
}
Exemple #3
0
/*
* 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 );
	}
}