//========= 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" ); } }