|
|
//========= 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
|