source-engine/game/shared/cstrike/flashbang_projectile.cpp

317 lines
9.2 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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" );
}