Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

384 lines
11 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "decoy_projectile.h"
#include "engine/IEngineSound.h"
#include "keyvalues.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "sendproxy.h"
#include "cs_player.h"
#include "bot_manager.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_DecoyProjectile, DT_DecoyProjectile, CDecoyProjectile )
END_RECV_TABLE()
//--------------------------------------------------------------------------------------------------------
void C_DecoyProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
{
if ( FStrEq( pszParticleName, "weapon_decoy_ground_effect" ) )
{
m_decoyParticleEffect = pNewParticleEffect;
}
}
//--------------------------------------------------------------------------------------------------------
void C_DecoyProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
{
if ( m_decoyParticleEffect == pParticleEffect )
{
m_decoyParticleEffect = NULL;
}
}
//--------------------------------------------------------------------------------------------------------
bool C_DecoyProjectile::Simulate( void )
{
// we are still moving
if ( GetAbsVelocity().Length() > 0.1f )
{
return true;
}
if ( !m_decoyParticleEffect.IsValid() )
{
DispatchParticleEffect( "weapon_decoy_ground_effect", PATTACH_POINT_FOLLOW, this, "Wick" );
}
else
{
m_decoyParticleEffect->SetSortOrigin( GetAbsOrigin() );
m_decoyParticleEffect->SetNeedsBBoxUpdate( true );
}
BaseClass::Simulate();
return true;
}
#else // GAME_DLL
#define GRENADE_MODEL "models/Weapons/w_eq_decoy_dropped.mdl"
LINK_ENTITY_TO_CLASS( decoy_projectile, CDecoyProjectile );
PRECACHE_REGISTER( decoy_projectile );
IMPLEMENT_SERVERCLASS_ST( CDecoyProjectile, DT_DecoyProjectile )
END_SEND_TABLE()
BEGIN_DATADESC( CDecoyProjectile )
DEFINE_THINKFUNC( Think_Detonate ),
DEFINE_THINKFUNC( GunfireThink )
END_DATADESC()
struct DecoyWeaponProfile
{
CSWeaponType weaponType;
int minShots;
int maxShots;
float extraDelay;
float pauseMin;
float pauseMax;
};
DecoyWeaponProfile gDecoyWeaponProfiles[] =
{
// CSWeaponType minShots, maxShots, extraDelay, pauseMin, pauseMax
{ WEAPONTYPE_PISTOL, 1, 3, 0.3f, 0.5f, 4.0f },
{ WEAPONTYPE_SUBMACHINEGUN, 1, 5, 0.0f, 0.5f, 4.0f },
{ WEAPONTYPE_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
{ WEAPONTYPE_SHOTGUN, 1, 3, 0.0f, 0.5f, 4.0f },
{ WEAPONTYPE_SNIPER_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
{ WEAPONTYPE_MACHINEGUN, 6, 20, 0.0f, 0.5f, 4.0f },
};
// --------------------------------------------------------------------------------------------------- //
// CFlashbangProjectile implementation.
// --------------------------------------------------------------------------------------------------- //
CDecoyProjectile* CDecoyProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo )
{
CDecoyProjectile *pGrenade = ( CDecoyProjectile* )CBaseEntity::Create( "decoy_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( 2.0f );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->m_flDamage = 25.0f; // 25 = 1/4 of HEGrenade Damage
pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
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_pWeaponInfo = &weaponInfo;
ASSERT(pOwner != NULL);
// pick a weapon based on what the player is carrying, falling back to default starting pistols
CBaseCombatWeapon* pPrimaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_RIFLE);
CBaseCombatWeapon* pSecondaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_PISTOL);
pGrenade->m_decoyWeaponDefIndex = INVALID_ITEM_DEF_INDEX;
pGrenade->m_decoyWeaponSoundType = SINGLE;
if ( pPrimaryWeapon != NULL )
{
CEconItemView* pItem = pPrimaryWeapon->GetEconItemView();
if ( pItem && pItem->IsValid() )
{
pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pPrimaryWeapon );
if ( pWeapon )
{
pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
}
}
else
{
pGrenade->m_decoyWeaponId = (CSWeaponID)pPrimaryWeapon->GetWeaponID();
}
}
else if ( pSecondaryWeapon != NULL )
{
CEconItemView* pItem = pSecondaryWeapon->GetEconItemView();
if ( pItem && pItem->IsValid() )
{
pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pSecondaryWeapon );
if ( pWeapon )
{
pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
}
}
else
{
pGrenade->m_decoyWeaponId = (CSWeaponID)pSecondaryWeapon->GetWeaponID();
}
}
else
{
if ( pOwner->GetTeamNumber() == TEAM_CT )
{
pGrenade->m_decoyWeaponId = WEAPON_HKP2000;
}
else
{
pGrenade->m_decoyWeaponId = WEAPON_GLOCK;
}
}
const CCSWeaponInfo* pDecoyWeaponInfo = GetWeaponInfo(pGrenade->m_decoyWeaponId);
// find the corresponding decoy firing profile
pGrenade->m_pProfile = &gDecoyWeaponProfiles[0];
for ( int i = 0; i < ARRAYSIZE( gDecoyWeaponProfiles ); ++i )
{
if ( gDecoyWeaponProfiles[i].weaponType == pDecoyWeaponInfo->GetWeaponType() )
{
pGrenade->m_pProfile = &gDecoyWeaponProfiles[i];
break;
}
}
pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CDecoyProjectile::SetTimer( float timer )
{
SetThink( &CDecoyProjectile::Think_Detonate );
SetNextThink( gpGlobals->curtime + timer );
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CDecoyProjectile::Think_Detonate( void )
{
#if 1
if ( GetAbsVelocity().Length() > 0.2f )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2f );
return;
}
#endif // 0
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_started" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
m_shotsRemaining = 0;
m_fExpireTime = gpGlobals->curtime + 14.0f; // TODO: Make this Data Driven
SetThink( &CDecoyProjectile::GunfireThink );
TheBots->SetGrenadeRadius( this, DecoyGrenadeRadius );
GunfireThink(); // This will handling the 'Detonate'
}
void CDecoyProjectile::Detonate( void )
{
// [mlowrance] The Decoy is handling it's own detonate.
Assert(!"Decoy grenade handles its own detonation");
}
void CDecoyProjectile::GunfireThink( void )
{
ASSERT(m_pProfile != NULL);
if ( !m_pProfile )
return;
if ( m_shotsRemaining <= 0 )
{
// pick a new burst activity
m_shotsRemaining = RandomInt( m_pProfile->minShots, m_pProfile->maxShots );
}
const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo(m_decoyWeaponId);
CBroadcastRecipientFilter filter;
const char *shootsound = pWeaponInfo->aShootSounds[ m_decoyWeaponSoundType ];
if ( m_decoyWeaponDefIndex != INVALID_ITEM_DEF_INDEX )
{
// Get the item definition
const CEconItemDefinition *pDef = ( m_decoyWeaponDefIndex > 0 ) ? GetItemSchema()->GetItemDefinition( m_decoyWeaponDefIndex ) : NULL;
if ( pDef )
{
const char *pszTempSound = pDef->GetWeaponReplacementSound( m_decoyWeaponSoundType );
if ( pszTempSound )
{
shootsound = pszTempSound;
}
}
}
CSoundParameters params;
if ( GetParametersForSound( shootsound, params, NULL ) )
{
CPASAttenuationFilter filter( this, params.soundlevel );
EmitSound( filter, entindex(), shootsound, &GetLocalOrigin(), 0.0f );
DispatchParticleEffect( "weapon_decoy_ground_effect_shot", GetAbsOrigin(), GetAbsAngles() );
}
// tell the bots about the gunfire
CCSPlayer *pPlayer = ToCSPlayer( GetThrower() );
if ( pPlayer )
{
// allow the bots to react to the "gunfire"
// we need a custom event here, because the "weapon_fire" event assumes
// the gunfire is coming from the player!
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_firing" );
if ( event )
{
event->SetInt( "userid", pPlayer->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
if ( --m_shotsRemaining > 0 )
{
SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( 0.0f, m_pProfile->extraDelay) );
return;
}
if ( gpGlobals->curtime < m_fExpireTime )
{
SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( m_pProfile->pauseMin, m_pProfile->pauseMax ) );
}
else
{
// [mlowrance] Do the damage on Despawn and post event
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "decoy_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
BaseClass::Detonate();
UTIL_Remove( this );
}
}
void CDecoyProjectile::Spawn( void )
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetBodygroupPreset( "thrown" );
}
void CDecoyProjectile::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "Flashbang.Explode" );
PrecacheScriptSound( "Flashbang.Bounce" );
PrecacheParticleSystem( "weapon_decoy_ground_effect_shot" );
BaseClass::Precache();
}
//TODO: Let physics handle the sound!
void CDecoyProjectile::BounceSound( void )
{
EmitSound( "Flashbang.Bounce" );
}
#endif // GAME_DLL