예제 #1
0
void CHL2MP_Player::Event_Killed( const CTakeDamageInfo &info )
{
	//update damage info with our accumulated physics force
	CTakeDamageInfo subinfo = info;
	subinfo.SetDamageForce( m_vecTotalBulletForce );

	//BP empêche de créer un ragdoll si on change de team en mode spectateur
	if(GetTeamNumber() != TEAM_SPECTATOR)
		CreateRagdollEntity();

	BaseClass::Event_Killed( subinfo );

	if ( info.GetDamageType() & DMG_DISSOLVE )
		if ( m_hRagdoll )
			m_hRagdoll->GetBaseAnimating()->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );

	CBaseEntity *pAttacker = info.GetAttacker();
	if ( pAttacker )
	{
		int iScoreToAdd = 1;

		if ( pAttacker == this)
		{
			if(HL2MPRules()->GetGameType() == GAME_TDM)
				iScoreToAdd = 0;
			else
				iScoreToAdd = -1;
		}

		if((HL2MPRules()->GetGameType() == GAME_FORTS) || (HL2MPRules()->GetGameType() == GAME_PUSH))
			iScoreToAdd = 0;

		GetGlobalTeam( pAttacker->GetTeamNumber() )->AddScore( iScoreToAdd );
	}

	FlashlightTurnOff();

	m_lifeState = LIFE_DEAD;

	RemoveEffects( EF_NODRAW );	// still draw player body
	StopZooming();
	DetonateTripmines();
//BP enregistre le tueur
	SetKiller(info.GetAttacker());
}
void CHL2MP_Player::Event_Killed( const CTakeDamageInfo &info )
{
	//update damage info with our accumulated physics force
	CTakeDamageInfo subinfo = info;
	subinfo.SetDamageForce( m_vecTotalBulletForce );

	SetNumAnimOverlays( 0 );

	// Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
	// because we still want to transmit to the clients in our PVS.
	CreateRagdollEntity();

	DetonateTripmines();

	BaseClass::Event_Killed( subinfo );

	if ( info.GetDamageType() & DMG_DISSOLVE )
	{
		if ( m_hRagdoll )
		{
			m_hRagdoll->GetBaseAnimating()->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );
		}
	}

	CBaseEntity *pAttacker = info.GetAttacker();

	if ( pAttacker )
	{
		int iScoreToAdd = 1;

		if ( pAttacker == this )
		{
			iScoreToAdd = -1;
		}

		GetGlobalTeam( pAttacker->GetTeamNumber() )->AddScore( iScoreToAdd );
	}

	FlashlightTurnOff();

	m_lifeState = LIFE_DEAD;

	RemoveEffects( EF_NODRAW );	// still draw player body
	StopZooming();
}
예제 #3
0
int CFuncShootBoost::OnTakeDamage(const CTakeDamageInfo &info)
{
    CBaseEntity *pInflictor = info.GetAttacker();
    if (pInflictor)
    {
        Vector finalVel = m_vPushDir.Normalized() * m_fPushForce;
        switch (m_iIncrease)
        {
        case 0:
            break;
        case 1:
            finalVel += pInflictor->GetAbsVelocity();
            break;
        case 2:
            if (finalVel.LengthSqr() < pInflictor->GetAbsVelocity().LengthSqr())
                finalVel = pInflictor->GetAbsVelocity();
            break;
        case 3: // The description of this method says the player velocity is increaed by final velocity,
            // but we're just adding one vec to the other, which is not quite the same
            if (finalVel.LengthSqr() < pInflictor->GetAbsVelocity().LengthSqr())
                finalVel += pInflictor->GetAbsVelocity();
            break;
        case 4:
            pInflictor->SetBaseVelocity(finalVel);
            break;
        default:
            DevWarning("CFuncShootBoost:: %i not recognised as valid for m_iIncrease", m_iIncrease);
            break;
        }
        if (m_Destination)
        {
            if (static_cast<CBaseTrigger *>(m_Destination)->IsTouching(pInflictor))
            {
                pInflictor->SetAbsVelocity(finalVel);
            }
        }
        else
        {
            pInflictor->SetAbsVelocity(finalVel);
        }
    }
    // As we don't want to break it, we don't call BaseClass::OnTakeDamage(info);
    // OnTakeDamage returns the damage dealt
    return info.GetDamage();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
float CNPC_CombineS::GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info )
{
	bool isNohead = false;
	switch( iHitGroup )
	{
	case HITGROUP_HEAD:
		int HeadshotRandom = random->RandomInt(0, 4);
		if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && g_fr_headshotgore.GetBool())
		{
			if (isNohead == false && HeadshotRandom == 0 && !(info.GetDamageType() & DMG_NEVERGIB) || isNohead == false && (info.GetDamageType() & (DMG_SNIPER | DMG_BUCKSHOT)) && !(info.GetDamageType() & DMG_NEVERGIB))
			{
				SetModel("models/gibs/combine_soldier_beheaded.mdl");
				DispatchParticleEffect("headshotspray", PATTACH_POINT_FOLLOW, this, "bloodspurt", true);
				SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage());
				CGib::SpawnSpecificGibs(this, 6, 750, 1500, "models/gibs/pgib_p3.mdl", 6);
				CGib::SpawnSpecificGibs(this, 6, 750, 1500, "models/gibs/pgib_p4.mdl", 6);
				EmitSound("Gore.Headshot");
				m_iHealth = 0;
				g_pGameRules->iHeadshotCount += 1;
				isNohead = true;
				CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
				if (g_fr_economy.GetBool())
				{
					pPlayer->AddMoney(5);
				}
				if (!g_fr_classic.GetBool())
				{
					pPlayer->AddXP(7);
				}
			}
			else
			{
				// Soldiers take double headshot damage
				return 2.0f;
			}
		}
		else
		{
			// Soldiers take double headshot damage
			return 2.0f;
		}
	}

	return BaseClass::GetHitgroupDamageMultiplier( iHitGroup, info );
}
int CHL2MP_Player::OnTakeDamage( const CTakeDamageInfo &inputInfo )
{
#ifndef GE_DLL
    //return here if the player is in the respawn grace period vs. slams.
    if ( gpGlobals->curtime < m_flSlamProtectTime &&  (inputInfo.GetDamageType() == DMG_BLAST ) )
        return 0;
    m_vecTotalBulletForce += inputInfo.GetDamageForce();
    gamestats->Event_PlayerDamage( this, inputInfo );
#else
    CBaseEntity *attacker = inputInfo.GetAttacker();
    Vector force = inputInfo.GetDamageForce();
    if ( force == vec3_origin && attacker )
    {
        Vector vecDir = vec3_origin;
        if ( inputInfo.GetInflictor() && GetMoveType() == MOVETYPE_WALK && !attacker->IsSolidFlagSet(FSOLID_TRIGGER) )
        {
            vecDir = inputInfo.GetInflictor()->WorldSpaceCenter() - Vector ( 0, 0, 10 ) - WorldSpaceCenter();
            VectorNormalize( vecDir );
            force = vecDir * -DamageForce( WorldAlignSize(), inputInfo.GetBaseDamage() );
        }
    }
    m_vecTotalBulletForce += force;
#endif

    return BaseClass::OnTakeDamage( inputInfo );
}
예제 #6
0
//------------------------------------------------------------------------------
// Purpose : 
// Input   :
// Output  :
//------------------------------------------------------------------------------
int CGrenadeHomer::OnTakeDamage( const CTakeDamageInfo &info )
{
	// Don't take damage from other homing grenades so can shoot in vollies
	if (FClassnameIs( info.GetInflictor(), "grenade_homer"))
	{
		return 0;
	}
	return BaseClass::OnTakeDamage( info );
}
예제 #7
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_AntlionGrub::Event_Killed( const CTakeDamageInfo &info )
{
	BaseClass::Event_Killed( info );

	if ( ( m_bSquashed == false ) && ( info.GetDamageType() & DMG_CLUB ) )
	{
		// Die!
		Squash( info.GetAttacker() );
	}
	else
	{
		//Restore this touch so we can still be squished
		SetTouch( GrubTouch );
	}

	// Slowly fade out glow out
	m_pGlowSprite->FadeAndDie( 5.0f );
}
예제 #8
0
// only shock damage counts as heavy (and thus causes a flinch even during normal running)
bool CASW_Harvester::IsHeavyDamage( const CTakeDamageInfo &info )
{
	// shock damage never causes flinching
	if (( info.GetDamageType() & DMG_SHOCK ) != 0 )
		return false;

	// explosions always cause a flinch
	if (( info.GetDamageType() & DMG_BLAST ) != 0 )
		return true;
	
	CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(info.GetAttacker());	
	if (pMarine && pMarine->GetActiveASWWeapon())
	{		
		return pMarine->GetActiveASWWeapon()->ShouldAlienFlinch(this, info);
	}

	return false;
}
예제 #9
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CObjectSapper::OnTakeDamage( const CTakeDamageInfo &info )
{
	if ( info.GetDamageCustom() != TF_DMG_WRENCH_FIX )
	{
		return 0;
	}

	return BaseClass::OnTakeDamage( info );
}
예제 #10
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int	CHL1_Player::OnTakeDamage( const CTakeDamageInfo &info )
{
	if ( info.GetDamage() > 0.0f )
	{
		m_flLastDamageTime = gpGlobals->curtime;
	}

	return BaseClass::OnTakeDamage( info );
}
//---------------------------------------------------------
//---------------------------------------------------------
int CRebelZombie::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
#ifndef HL2_EPISODIC
	if ( inputInfo.GetDamageType() & DMG_BUCKSHOT )
	{
		if( inputInfo.GetDamage() > (m_iMaxHealth/3) )
		{
			// Always flinch if damaged a lot by buckshot, even if not shot in the head.
			// The reason for making sure we did at least 1/3rd of the zombie's max health
			// is so the zombie doesn't flinch every time the odd shotgun pellet hits them,
			// and so the maximum number of times you'll see a zombie flinch like this is 2.(sjb)
			AddGesture( ACT_GESTURE_FLINCH_HEAD );
		}
	}
#endif // HL2_EPISODIC

	return BaseClass::OnTakeDamage_Alive( inputInfo );
}
예제 #12
0
//---------------------------------------------------------
//---------------------------------------------------------
int CNPC_Roller::VPhysicsTakeDamage( const CTakeDamageInfo &info )
{
	if( RollerPhysicsDamageMask() & info.GetDamageType() )
	{
		SetCondition( COND_ROLLER_PHYSICS );
	}

	return BaseClass::VPhysicsTakeDamage( info );
}
예제 #13
0
int CASW_Parasite::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
	int result = 0;

	// scale damage up while in the air
	if (m_bMidJump)
	{
		CTakeDamageInfo newDamage = info;		
		newDamage.ScaleDamage(10.0f);
		result = BaseClass::OnTakeDamage_Alive(newDamage);
	}
	else
	{
		result = BaseClass::OnTakeDamage_Alive(info);
	}

	return result;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
void CNPC_CombineShot::Event_Killed(const CTakeDamageInfo &info)
{
	// Don't bother if we've been told not to, or the player has a megaphyscannon
	if ( combine_shot_spawn_health.GetBool() == false || PlayerHasMegaPhysCannon() )
	{
		BaseClass::Event_Killed( info );
		return;
	}

	CBasePlayer *pPlayer = ToBasePlayer( info.GetAttacker() );

	if ( !pPlayer )
	{
		CPropVehicleDriveable *pVehicle = dynamic_cast<CPropVehicleDriveable *>( info.GetAttacker() ) ;
		if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() )
		{
			pPlayer = assert_cast<CBasePlayer *>( pVehicle->GetDriver() );
		}
	}

	if ( pPlayer != NULL )
	{
		CHalfLife2 *pHL2GameRules = static_cast<CHalfLife2 *>(g_pGameRules);

		// Attempt to drop health
		if ( pHL2GameRules->NPC_ShouldDropHealth( pPlayer ) )
		{
			DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) );
			pHL2GameRules->NPC_DroppedHealth();
		}
		
		if ( HasSpawnFlags( SF_COMBINE_NO_GRENADEDROP ) == false )
		{
			// Attempt to drop a grenade
			if ( pHL2GameRules->NPC_ShouldDropGrenade( pPlayer ) )
			{
				DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) );
				pHL2GameRules->NPC_DroppedGrenade();
			}
		}
	}

	BaseClass::Event_Killed( info );
}
예제 #15
0
//-----------------------------------------------------------------------------
// Purpose: We have been damaged. Possibly activate, depending on our flags.
// Input  : pInflictor - 
//			pAttacker - 
//			flDamage - 
//			bitsDamageType - 
// Output : 
//-----------------------------------------------------------------------------
int CBaseButton::OnTakeDamage( const CTakeDamageInfo &info )
{
	m_OnDamaged.FireOutput(m_hActivator, this);

	// dvsents2: remove obselete health keyvalue from func_button
	if (!HasSpawnFlags(SF_BUTTON_DAMAGE_ACTIVATES) && (m_iHealth == 0))
	{
		return(0);
	}

	BUTTON_CODE code = ButtonResponseToTouch();

	if ( code == BUTTON_NOTHING )
		return 0;

	m_hActivator = info.GetAttacker();

	// dvsents2: why would activator be NULL here?
	if ( m_hActivator == NULL )
		return 0;

	if (m_bLocked)
	{
		return(0);
	}

	// Temporarily disable the touch function, until movement is finished.
	SetTouch( NULL );

	if ( code == BUTTON_RETURN )
	{
		if ( m_sNoise != NULL_STRING )
		{
			CPASAttenuationFilter filter( this );

			EmitSound_t ep;
			ep.m_nChannel = CHAN_VOICE;
			ep.m_pSoundName = (char*)STRING(m_sNoise);
			ep.m_flVolume = 1;
			ep.m_SoundLevel = SNDLVL_NORM;

			EmitSound( filter, entindex(), ep );
		}

		m_OnPressed.FireOutput(m_hActivator, this);
		ButtonReturn();
	}
	else
	{
		// code == BUTTON_ACTIVATE
		m_OnPressed.FireOutput(m_hActivator, this);
		ButtonActivate( );
	}

	return 0;
}
예제 #16
0
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CUnitBase::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	Vector vecOrigin = ptr->endpos - vecDir * 4;

	if ( m_takedamage )
	{
		AddMultiDamage( info, this );

		// Must always be called from the client to save data
#ifdef CLIENT_DLL
		int blood = BloodColor();
		if ( blood != DONT_BLEED )
		{
			SpawnBlood( vecOrigin, vecDir, blood, info.GetDamage() );// a little surface blood.
			TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() );
		}
#endif // CLIENT_DLL
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  :
// Output : 
//-----------------------------------------------------------------------------
void CBaseHelicopter::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	// Take no damage from trace attacks unless it's blast damage. RadiusDamage() sometimes calls
	// TraceAttack() as a means for delivering blast damage. Usually when the explosive penetrates
	// the target. (RPG missiles do this sometimes).
	if( info.GetDamageType() & (DMG_BLAST|DMG_AIRBOAT) )
	{
		BaseClass::TraceAttack( info, vecDir, ptr );
	}
}
예제 #18
0
void CEP2GameStats::Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info )
{
	BaseClass::Event_WeaponHit( pShooter, bPrimary, pchWeaponName, info );
	Ep2LevelStats_t::WeaponLump_t *lump = FindWeaponsLump( pchWeaponName, bPrimary );
	if ( lump )
	{
		++lump->m_nHits;
		lump->m_flDamageInflicted += info.GetDamage();
	}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CTFGrenadeMirvProjectile::OnTakeDamage( const CTakeDamageInfo &info )
{
	if ( !info.GetAttacker() )
		return 0;

	if ( info.GetAttacker()->GetTeamNumber() == GetTeamNumber() )
		return 0;

	// Wrench hit defuses the dynamite pack.
	if ( info.GetDamageCustom() == TF_DMG_WRENCH_FIX )
	{
		SetThink( &CBaseEntity::SUB_Remove );
		SetNextThink( gpGlobals->curtime + 5.0f );

		return 1;
	}

	return 0;
}
예제 #20
0
void CAI_PlayerAlly::Event_Killed( const CTakeDamageInfo &info )
{
	AlertFriends( info.GetAttacker() );

	SetTarget( NULL );
	// Don't finish that sentence
	StopTalking();
	SetUse( NULL );
	BaseClass::Event_Killed( info );
}
예제 #21
0
void CTalkMonster::OnTakeDamage( const CTakeDamageInfo& info )
{
	if ( IsAlive() )
	{
		// if player damaged this entity, have other friends talk about it
		if (info.GetAttacker() && m_MonsterState != MONSTERSTATE_PRONE && info.GetAttacker()->GetFlags().Any( FL_CLIENT ) )
		{
			CBaseEntity *pFriend = FindNearestFriend( false );

			if (pFriend && pFriend->IsAlive())
			{
				// only if not dead or dying!
				CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend;
				pTalkMonster->ChangeSchedule( slIdleStopShooting );
			}
		}
	}
	CBaseMonster::OnTakeDamage( info );
}
예제 #22
0
void CPhysicsCannister::TraceAttack( const CTakeDamageInfo &info, const Vector &dir, trace_t *ptr )
{
	if ( !m_active && ptr->hitgroup != 0 )
	{
		Vector direction = -dir;
		direction.z -= 5;
		VectorNormalize( direction );
		CannisterActivate( info.GetAttacker(), direction );
	}
	BaseClass::TraceAttack( info, dir, ptr );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponBrickbat::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	if ( info.GetDamageType() & DMG_BULLET)
	{
		if ( BrickBatAmmoArray[m_iCurrentAmmoType].m_nAmmoType == BRICKBAT_ROCK )
		{
			g_pEffects->Ricochet(ptr->endpos,ptr->plane.normal);
		}	
	}
	BaseClass::TraceAttack( info, vecDir, ptr );
}
예제 #24
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CWeaponStriderBuster::BusterDetachThink()
{
	SetNextThink( gpGlobals->curtime + 0.1f );

	trace_t tr;
	UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 1200), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );

	if( fabs(tr.startpos.z - tr.endpos.z) < 240.0f )
	{
		SetThink(NULL);
		EmitSound( "Weapon_StriderBuster.Dud_Detonate" );
		DispatchParticleEffect( "striderbuster_break_flechette", GetAbsOrigin(), GetAbsAngles() );
		SetHealth( 0 );
		CTakeDamageInfo info;
		info.SetDamage( 1.0f );
		info.SetAttacker( this );
		info.SetInflictor( this );
		Shatter(this);
	}
}
예제 #25
0
int CGrenadeFrag::OnTakeDamage( const CTakeDamageInfo &inputInfo )
{
	// Manually apply vphysics because BaseCombatCharacter takedamage doesn't call back to CBaseEntity OnTakeDamage
	VPhysicsTakeDamage( inputInfo );

	// Grenades only suffer blast damage and burn damage.
	if( !(inputInfo.GetDamageType() & (DMG_BLAST|DMG_BURN) ) )
		return 0;

	return BaseClass::OnTakeDamage( inputInfo );
}
예제 #26
0
void CASW_Parasite::Event_Killed( const CTakeDamageInfo &info )
{
	if (GetMother())
		GetMother()->ChildAlienKilled(this);

	BaseClass::Event_Killed( info );

	if ( !m_bDefanged && !m_bDoEggIdle.Get() && ( info.GetDamageType() & DMG_CLUB ) && info.GetAttacker() && info.GetAttacker()->Classify() == CLASS_ASW_MARINE )
	{
		CASW_Marine *pMarine = static_cast<CASW_Marine*>( info.GetAttacker() );
		if ( pMarine && pMarine->IsInhabited() && pMarine->GetCommander() )
		{
			pMarine->GetCommander()->AwardAchievement( ACHIEVEMENT_ASW_MELEE_PARASITE );
			if ( pMarine->GetMarineResource() )
			{
				pMarine->GetMarineResource()->m_bMeleeParasiteKill = true;
			}
		}
	}
}
예제 #27
0
int CRocketMissile::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
	if ( ( info.GetDamageType() & (DMG_AIRBOAT) ) == false )
	{
		return 0;
	}

	int nRetVal = BaseClass::OnTakeDamage_Alive( info );

	return nRetVal;
}
예제 #28
0
//-----------------------------------------------------------------------------
// Purpose: allows the crate to open up when hit by a crowbar
//-----------------------------------------------------------------------------
int CItem_AmmoCrate::OnTakeDamage( const CTakeDamageInfo &info )
{
	// if it's the player hitting us with a crowbar, open up
	CBasePlayer *player = ToBasePlayer(info.GetAttacker());
	if (player)
	{
		CBaseCombatWeapon *weapon = player->GetActiveWeapon();

		if (weapon && !stricmp(weapon->GetName(), "weapon_crowbar"))
		{
			// play the normal use sound
			player->EmitSound( "HL2Player.Use" );
			// open the crate
			Use(info.GetAttacker(), info.GetAttacker(), USE_TOGGLE, 0.0f);
		}
	}

	// don't actually take any damage
	return 0;
}
예제 #29
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CPropJetski::OnTakeDamage( const CTakeDamageInfo &info )
{
	//Do scaled up physic damage to the car
	CTakeDamageInfo physDmg = info;
	physDmg.ScaleDamage( 25 );
	VPhysicsTakeDamage( physDmg );

	//Check to do damage to driver
	if ( m_hPlayer != NULL )
	{
		//Take no damage from physics damages
		if ( info.GetDamageType() & DMG_CRUSH )
			return 0;

		//Take the damage
		m_hPlayer->TakeDamage( info );
	}

	return 0;
}
예제 #30
0
void CNPC_Zombine::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
	BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );

	//Only knock grenades off their hands if it's a player doing the damage.
	if ( info.GetAttacker() && info.GetAttacker()->IsNPC() )
		return;

	if ( info.GetDamageType() & ( DMG_BULLET | DMG_CLUB ) )
	{
		if ( ptr->hitgroup == HITGROUP_LEFTARM )
		{
			if ( HasGrenade() )
			{
				DropGrenade( info.GetDamageForce() );
				StopSprint();
			}
		}
	}
}