You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
9.2 KiB
316 lines
9.2 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "flashbang_projectile.h" |
|
#include "shake.h" |
|
#include "engine/IEngineSound.h" |
|
#include "cs_player.h" |
|
#include "dlight.h" |
|
#include "KeyValues.h" |
|
#include "weapon_csbase.h" |
|
#include "collisionutils.h" |
|
#include "particle_smokegrenade.h" |
|
#include "smoke_fog_overlay_shared.h" |
|
|
|
#define GRENADE_MODEL "models/Weapons/w_eq_flashbang_thrown.mdl" |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( flashbang_projectile, CFlashbangProjectile ); |
|
PRECACHE_WEAPON_REGISTER( flashbang_projectile ); |
|
|
|
float PercentageOfFlashForPlayer(CBaseEntity *player, Vector flashPos, CBaseEntity *pevInflictor) |
|
{ |
|
float retval = 0.0f; |
|
|
|
trace_t tr; |
|
|
|
Vector pos = player->EyePosition(); |
|
Vector vecRight, vecUp, vecForward; |
|
AngleVectors( player->EyeAngles(), &vecForward ); |
|
|
|
QAngle tempAngle; |
|
VectorAngles(player->EyePosition() - flashPos, tempAngle); |
|
AngleVectors(tempAngle, NULL, &vecRight, &vecUp); |
|
|
|
vecRight.NormalizeInPlace(); |
|
vecUp.NormalizeInPlace(); |
|
|
|
UTIL_TraceLine( flashPos, pos, |
|
(CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_DEBRIS|CONTENTS_MONSTER), |
|
pevInflictor, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if ((tr.fraction == 1.0) || (tr.m_pEnt == player)) |
|
{ |
|
retval = 1.0; |
|
} |
|
else |
|
{ |
|
return 0.0; |
|
} |
|
|
|
CBaseEntity *pSGren; |
|
|
|
for( pSGren = gEntList.FindEntityByClassname( NULL, "env_particlesmokegrenade" ); |
|
pSGren; |
|
pSGren = gEntList.FindEntityByClassname( pSGren, "env_particlesmokegrenade" ) ) |
|
{ |
|
ParticleSmokeGrenade *pPSG =( ParticleSmokeGrenade* ) pSGren; |
|
|
|
if ( gpGlobals->curtime > pPSG->m_flSpawnTime + pPSG->m_FadeStartTime ) // ignore the smoke grenade if it's fading. |
|
continue; |
|
|
|
float flHit1, flHit2; |
|
|
|
float flInnerRadius = SMOKEGRENADE_PARTICLERADIUS; |
|
// float flOutterRadius = flInnerRadius + ( 0.5 * SMOKEPARTICLE_SIZE ); |
|
|
|
Vector vPos = pSGren->GetAbsOrigin(); |
|
|
|
/*debugoverlay->AddBoxOverlay( pSGren->GetAbsOrigin(), Vector( flInnerRadius, flInnerRadius, flInnerRadius ), |
|
Vector( -flInnerRadius, -flInnerRadius, -flInnerRadius ), QAngle( 0, 0, 0 ), 0, 255, 0, 30, 10 ); |
|
debugoverlay->AddBoxOverlay( pSGren->GetAbsOrigin(), Vector( flOutterRadius, flOutterRadius, flOutterRadius ), |
|
Vector( -flOutterRadius, -flOutterRadius, -flOutterRadius ), QAngle( 0, 0, 0 ), 255, 0, 0, 30, 10 ); */ |
|
|
|
if ( IntersectInfiniteRayWithSphere( pos, vecForward, vPos, flInnerRadius, &flHit1, &flHit2 ) ) |
|
{ |
|
retval *= 0.8; |
|
} |
|
/* else if ( IntersectInfiniteRayWithSphere( pos, vecForward, vPos, flOutterRadius, &flHit1, &flHit2 ) ) |
|
{ |
|
retval *= 0.9; |
|
} |
|
*/ |
|
} |
|
|
|
return retval; |
|
|
|
} |
|
|
|
// --------------------------------------------------------------------------------------------------- // |
|
// |
|
// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. |
|
// |
|
// only damage ents that can clearly be seen by the explosion! |
|
// --------------------------------------------------------------------------------------------------- // |
|
|
|
void RadiusFlash( |
|
Vector vecSrc, |
|
CBaseEntity *pevInflictor, |
|
CBaseEntity *pevAttacker, |
|
float flDamage, |
|
int iClassIgnore, |
|
int bitsDamageType ) |
|
{ |
|
vecSrc.z += 1;// in case grenade is lying on the ground |
|
|
|
if ( !pevAttacker ) |
|
pevAttacker = pevInflictor; |
|
|
|
trace_t tr; |
|
float flAdjustedDamage; |
|
variant_t var; |
|
Vector vecEyePos; |
|
float fadeTime, fadeHold; |
|
Vector vForward; |
|
Vector vecLOS; |
|
float flDot; |
|
|
|
CBaseEntity *pEntity = NULL; |
|
static float flRadius = 1500; |
|
float falloff = flDamage / flRadius; |
|
|
|
bool bInWater = (UTIL_PointContents( vecSrc ) == CONTENTS_WATER); |
|
|
|
// iterate on all entities in the vicinity. |
|
while ((pEntity = gEntList.FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) |
|
{ |
|
bool bPlayer = pEntity->IsPlayer(); |
|
bool bHostage = ( Q_stricmp( pEntity->GetClassname(), "hostage_entity" ) == 0 ); |
|
|
|
if( !bPlayer && !bHostage ) |
|
continue; |
|
|
|
vecEyePos = pEntity->EyePosition(); |
|
|
|
// blasts don't travel into or out of water |
|
if ( bInWater && pEntity->GetWaterLevel() == 0) |
|
continue; |
|
if (!bInWater && pEntity->GetWaterLevel() == 3) |
|
continue; |
|
|
|
float percentageOfFlash = PercentageOfFlashForPlayer(pEntity, vecSrc, pevInflictor); |
|
|
|
if ( percentageOfFlash > 0.0 ) |
|
{ |
|
// decrease damage for an ent that's farther from the grenade |
|
flAdjustedDamage = flDamage - ( vecSrc - pEntity->EyePosition() ).Length() * falloff; |
|
|
|
if ( flAdjustedDamage > 0 ) |
|
{ |
|
// See if we were facing the flash |
|
AngleVectors( pEntity->EyeAngles(), &vForward ); |
|
|
|
vecLOS = ( vecSrc - vecEyePos ); |
|
|
|
float flDistance = vecLOS.Length(); |
|
|
|
// Normalize both vectors so the dotproduct is in the range -1.0 <= x <= 1.0 |
|
vecLOS.NormalizeInPlace(); |
|
|
|
flDot = DotProduct (vecLOS, vForward); |
|
|
|
float startingAlpha = 255; |
|
|
|
// if target is facing the bomb, the effect lasts longer |
|
if( flDot >= 0.5 ) |
|
{ |
|
// looking at the flashbang |
|
fadeTime = flAdjustedDamage * 2.5f; |
|
fadeHold = flAdjustedDamage * 1.25f; |
|
} |
|
else if( flDot >= -0.5 ) |
|
{ |
|
// looking to the side |
|
fadeTime = flAdjustedDamage * 1.75f; |
|
fadeHold = flAdjustedDamage * 0.8f; |
|
} |
|
else |
|
{ |
|
// facing away |
|
fadeTime = flAdjustedDamage * 1.0f; |
|
fadeHold = flAdjustedDamage * 0.75f; |
|
startingAlpha = 200; |
|
} |
|
|
|
fadeTime *= percentageOfFlash; |
|
fadeHold *= percentageOfFlash; |
|
|
|
if ( bPlayer ) |
|
{ |
|
// blind players and bots |
|
CCSPlayer *player = static_cast< CCSPlayer * >( pEntity ); |
|
|
|
//============================================================================= |
|
// HPE_BEGIN: |
|
// [tj] Store who was responsible for the most recent flashbang blinding. |
|
//============================================================================= |
|
|
|
CCSPlayer *attacker = ToCSPlayer (pevAttacker); |
|
if (attacker && player) |
|
{ |
|
player->SetLastFlashbangAttacker(attacker); |
|
} |
|
|
|
//============================================================================= |
|
// HPE_END |
|
//============================================================================= |
|
|
|
|
|
|
|
player->Blind( fadeHold, fadeTime, startingAlpha ); |
|
|
|
// deafen players and bots |
|
player->Deafen( flDistance ); |
|
} |
|
else if ( bHostage ) |
|
{ |
|
variant_t val; |
|
val.SetFloat( fadeTime ); |
|
pEntity->AcceptInput( "flashbang", pevInflictor, pevAttacker, val, 0 ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
CPVSFilter filter(vecSrc); |
|
te->DynamicLight( filter, 0.0, &vecSrc, 255, 255, 255, 2, 400, 0.1, 768 ); |
|
} |
|
|
|
// --------------------------------------------------------------------------------------------------- // |
|
// CFlashbangProjectile implementation. |
|
// --------------------------------------------------------------------------------------------------- // |
|
|
|
CFlashbangProjectile* CFlashbangProjectile::Create( |
|
const Vector &position, |
|
const QAngle &angles, |
|
const Vector &velocity, |
|
const AngularImpulse &angVelocity, |
|
CBaseCombatCharacter *pOwner ) |
|
{ |
|
CFlashbangProjectile *pGrenade = (CFlashbangProjectile*)CBaseEntity::Create( "flashbang_projectile", position, angles, pOwner ); |
|
|
|
// Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER |
|
// one second before detonation. |
|
pGrenade->SetAbsVelocity( velocity ); |
|
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity ); |
|
pGrenade->SetThrower( pOwner ); |
|
pGrenade->m_flDamage = 100; |
|
pGrenade->ChangeTeam( pOwner->GetTeamNumber() ); |
|
|
|
pGrenade->SetTouch( &CBaseGrenade::BounceTouch ); |
|
|
|
pGrenade->SetThink( &CBaseCSGrenadeProjectile::DangerSoundThink ); |
|
pGrenade->SetNextThink( gpGlobals->curtime ); |
|
|
|
pGrenade->SetDetonateTimerLength( 1.5 ); |
|
|
|
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity ); |
|
|
|
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() ); |
|
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() ); |
|
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() ); |
|
|
|
pGrenade->m_pWeaponInfo = GetWeaponInfo( WEAPON_FLASHBANG ); |
|
|
|
|
|
return pGrenade; |
|
} |
|
|
|
void CFlashbangProjectile::Spawn() |
|
{ |
|
SetModel( GRENADE_MODEL ); |
|
BaseClass::Spawn(); |
|
} |
|
|
|
void CFlashbangProjectile::Precache() |
|
{ |
|
PrecacheModel( GRENADE_MODEL ); |
|
|
|
PrecacheScriptSound( "Flashbang.Explode" ); |
|
PrecacheScriptSound( "Flashbang.Bounce" ); |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
void CFlashbangProjectile::Detonate() |
|
{ |
|
RadiusFlash ( GetAbsOrigin(), this, GetThrower(), 4, CLASS_NONE, DMG_BLAST ); |
|
EmitSound( "Flashbang.Explode" ); |
|
|
|
// tell the bots a flashbang grenade has exploded |
|
CCSPlayer *player = ToCSPlayer(GetThrower()); |
|
if ( player ) |
|
{ |
|
IGameEvent * event = gameeventmanager->CreateEvent( "flashbang_detonate" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "userid", player->GetUserID() ); |
|
event->SetFloat( "x", GetAbsOrigin().x ); |
|
event->SetFloat( "y", GetAbsOrigin().y ); |
|
event->SetFloat( "z", GetAbsOrigin().z ); |
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
|
|
UTIL_Remove( this ); |
|
} |
|
|
|
//TODO: Let physics handle the sound! |
|
void CFlashbangProjectile::BounceSound( void ) |
|
{ |
|
EmitSound( "Flashbang.Bounce" ); |
|
}
|
|
|