mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
317 lines
9.2 KiB
C++
317 lines
9.2 KiB
C++
|
//========= 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" );
|
||
|
}
|