source-engine/game/server/cstrike/smokegrenade_projectile.cpp
2022-03-02 11:45:17 +03:00

190 lines
5.1 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "smokegrenade_projectile.h"
#include "sendproxy.h"
#include "particle_smokegrenade.h"
#include "cs_player.h"
#include "KeyValues.h"
#include "bot_manager.h"
#include "weapon_csbase.h"
#define GRENADE_MODEL "models/Weapons/w_eq_smokegrenade_thrown.mdl"
LINK_ENTITY_TO_CLASS( smokegrenade_projectile, CSmokeGrenadeProjectile );
PRECACHE_WEAPON_REGISTER( smokegrenade_projectile );
BEGIN_DATADESC( CSmokeGrenadeProjectile )
DEFINE_THINKFUNC( Think_Detonate ),
DEFINE_THINKFUNC( Think_Fade ),
DEFINE_THINKFUNC( Think_Remove )
END_DATADESC()
CSmokeGrenadeProjectile* CSmokeGrenadeProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner )
{
CSmokeGrenadeProjectile *pGrenade = (CSmokeGrenadeProjectile*)CBaseEntity::Create( "smokegrenade_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->SetTimer( 1.5 );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->SetGravity( 0.55 );
pGrenade->SetFriction( 0.7 );
pGrenade->m_flDamage = 100;
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
pGrenade->SetTouch( &CBaseGrenade::BounceTouch );
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
pGrenade->m_bDidSmokeEffect = false;
pGrenade->m_pWeaponInfo = GetWeaponInfo( WEAPON_SMOKEGRENADE );
return pGrenade;
}
void CSmokeGrenadeProjectile::SetTimer( float timer )
{
SetThink( &CSmokeGrenadeProjectile::Think_Detonate );
SetNextThink( gpGlobals->curtime + timer );
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CSmokeGrenadeProjectile::Think_Detonate()
{
if ( GetAbsVelocity().Length() > 0.1 )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2 );
return;
}
TheBots->SetGrenadeRadius( this, SmokeGrenadeRadius );
// Ok, we've stopped rolling or whatever. Now detonate.
ParticleSmokeGrenade *pGren = (ParticleSmokeGrenade*)CBaseEntity::Create( PARTICLESMOKEGRENADE_ENTITYNAME, GetAbsOrigin(), QAngle(0,0,0), NULL );
if ( pGren )
{
pGren->FillVolume();
pGren->SetFadeTime( 15, 20 );
pGren->SetAbsOrigin( GetAbsOrigin() );
//tell the hostages about the smoke!
CBaseEntity *pEntity = NULL;
variant_t var; //send the location of the smoke?
var.SetVector3D( GetAbsOrigin() );
while ( ( pEntity = gEntList.FindEntityByClassname( pEntity, "hostage_entity" ) ) != NULL)
{
//send to hostages that have a resonable chance of being in it while its still smoking
if( (GetAbsOrigin() - pEntity->GetAbsOrigin()).Length() < 1000 )
pEntity->AcceptInput( "smokegrenade", this, this, var, 0 );
}
// tell the bots a smoke grenade has exploded
CCSPlayer *player = ToCSPlayer(GetThrower());
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "smokegrenade_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 );
}
}
}
m_hSmokeEffect = pGren;
m_bDidSmokeEffect = true;
EmitSound( "BaseSmokeEffect.Sound" );
m_nRenderMode = kRenderTransColor;
SetNextThink( gpGlobals->curtime + 5 );
SetThink( &CSmokeGrenadeProjectile::Think_Fade );
}
// Fade the projectile out over time before making it disappear
void CSmokeGrenadeProjectile::Think_Fade()
{
SetNextThink( gpGlobals->curtime );
color32 c = GetRenderColor();
c.a -= 1;
SetRenderColor( c.r, c.b, c.g, c.a );
if ( !c.a )
{
TheBots->RemoveGrenade( this );
SetModelName( NULL_STRING );//invisible
SetNextThink( gpGlobals->curtime + 20 );
SetThink( &CSmokeGrenadeProjectile::Think_Remove ); // Spit out smoke for 10 seconds.
SetSolid( SOLID_NONE );
}
}
void CSmokeGrenadeProjectile::Think_Remove()
{
if ( m_hSmokeEffect.Get() )
UTIL_Remove( m_hSmokeEffect );
TheBots->RemoveGrenade( this );
SetModelName( NULL_STRING );//invisible
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
//Implement this so we never call the base class,
//but this should never be called either.
void CSmokeGrenadeProjectile::Detonate( void )
{
Assert(!"Smoke grenade handles its own detonation");
}
void CSmokeGrenadeProjectile::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CSmokeGrenadeProjectile::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "BaseSmokeEffect.Sound" );
PrecacheScriptSound( "SmokeGrenade.Bounce" );
BaseClass::Precache();
}
void CSmokeGrenadeProjectile::BounceSound( void )
{
if ( !m_bDidSmokeEffect )
{
EmitSound( "SmokeGrenade.Bounce" );
}
}