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

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "decoy_projectile.h"
  8. #include "engine/IEngineSound.h"
  9. #include "keyvalues.h"
  10. #include "weapon_csbase.h"
  11. #include "particle_parse.h"
  12. #if defined( CLIENT_DLL )
  13. #include "c_cs_player.h"
  14. #else
  15. #include "sendproxy.h"
  16. #include "cs_player.h"
  17. #include "bot_manager.h"
  18. #endif
  19. // NOTE: This has to be the last file included!
  20. #include "tier0/memdbgon.h"
  21. #if defined( CLIENT_DLL )
  22. IMPLEMENT_CLIENTCLASS_DT( C_DecoyProjectile, DT_DecoyProjectile, CDecoyProjectile )
  23. END_RECV_TABLE()
  24. //--------------------------------------------------------------------------------------------------------
  25. void C_DecoyProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
  26. {
  27. if ( FStrEq( pszParticleName, "weapon_decoy_ground_effect" ) )
  28. {
  29. m_decoyParticleEffect = pNewParticleEffect;
  30. }
  31. }
  32. //--------------------------------------------------------------------------------------------------------
  33. void C_DecoyProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
  34. {
  35. if ( m_decoyParticleEffect == pParticleEffect )
  36. {
  37. m_decoyParticleEffect = NULL;
  38. }
  39. }
  40. //--------------------------------------------------------------------------------------------------------
  41. bool C_DecoyProjectile::Simulate( void )
  42. {
  43. // we are still moving
  44. if ( GetAbsVelocity().Length() > 0.1f )
  45. {
  46. return true;
  47. }
  48. if ( !m_decoyParticleEffect.IsValid() )
  49. {
  50. DispatchParticleEffect( "weapon_decoy_ground_effect", PATTACH_POINT_FOLLOW, this, "Wick" );
  51. }
  52. else
  53. {
  54. m_decoyParticleEffect->SetSortOrigin( GetAbsOrigin() );
  55. m_decoyParticleEffect->SetNeedsBBoxUpdate( true );
  56. }
  57. BaseClass::Simulate();
  58. return true;
  59. }
  60. #else // GAME_DLL
  61. #define GRENADE_MODEL "models/Weapons/w_eq_decoy_dropped.mdl"
  62. LINK_ENTITY_TO_CLASS( decoy_projectile, CDecoyProjectile );
  63. PRECACHE_REGISTER( decoy_projectile );
  64. IMPLEMENT_SERVERCLASS_ST( CDecoyProjectile, DT_DecoyProjectile )
  65. END_SEND_TABLE()
  66. BEGIN_DATADESC( CDecoyProjectile )
  67. DEFINE_THINKFUNC( Think_Detonate ),
  68. DEFINE_THINKFUNC( GunfireThink )
  69. END_DATADESC()
  70. struct DecoyWeaponProfile
  71. {
  72. CSWeaponType weaponType;
  73. int minShots;
  74. int maxShots;
  75. float extraDelay;
  76. float pauseMin;
  77. float pauseMax;
  78. };
  79. DecoyWeaponProfile gDecoyWeaponProfiles[] =
  80. {
  81. // CSWeaponType minShots, maxShots, extraDelay, pauseMin, pauseMax
  82. { WEAPONTYPE_PISTOL, 1, 3, 0.3f, 0.5f, 4.0f },
  83. { WEAPONTYPE_SUBMACHINEGUN, 1, 5, 0.0f, 0.5f, 4.0f },
  84. { WEAPONTYPE_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
  85. { WEAPONTYPE_SHOTGUN, 1, 3, 0.0f, 0.5f, 4.0f },
  86. { WEAPONTYPE_SNIPER_RIFLE, 1, 3, 0.5f, 0.5f, 4.0f },
  87. { WEAPONTYPE_MACHINEGUN, 6, 20, 0.0f, 0.5f, 4.0f },
  88. };
  89. // --------------------------------------------------------------------------------------------------- //
  90. // CFlashbangProjectile implementation.
  91. // --------------------------------------------------------------------------------------------------- //
  92. CDecoyProjectile* CDecoyProjectile::Create(
  93. const Vector &position,
  94. const QAngle &angles,
  95. const Vector &velocity,
  96. const AngularImpulse &angVelocity,
  97. CBaseCombatCharacter *pOwner,
  98. const CCSWeaponInfo& weaponInfo )
  99. {
  100. CDecoyProjectile *pGrenade = ( CDecoyProjectile* )CBaseEntity::Create( "decoy_projectile", position, angles, pOwner );
  101. // Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER
  102. // one second before detonation.
  103. pGrenade->SetTimer( 2.0f );
  104. pGrenade->SetAbsVelocity( velocity );
  105. pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
  106. pGrenade->SetThrower( pOwner );
  107. pGrenade->m_flDamage = 25.0f; // 25 = 1/4 of HEGrenade Damage
  108. pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
  109. pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
  110. pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity );
  111. pGrenade->SetTouch( &CBaseGrenade::BounceTouch );
  112. pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
  113. pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
  114. pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
  115. pGrenade->m_pWeaponInfo = &weaponInfo;
  116. ASSERT(pOwner != NULL);
  117. // pick a weapon based on what the player is carrying, falling back to default starting pistols
  118. CBaseCombatWeapon* pPrimaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_RIFLE);
  119. CBaseCombatWeapon* pSecondaryWeapon = pOwner->Weapon_GetSlot(WEAPON_SLOT_PISTOL);
  120. pGrenade->m_decoyWeaponDefIndex = INVALID_ITEM_DEF_INDEX;
  121. pGrenade->m_decoyWeaponSoundType = SINGLE;
  122. if ( pPrimaryWeapon != NULL )
  123. {
  124. CEconItemView* pItem = pPrimaryWeapon->GetEconItemView();
  125. if ( pItem && pItem->IsValid() )
  126. {
  127. pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
  128. pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
  129. CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pPrimaryWeapon );
  130. if ( pWeapon )
  131. {
  132. pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
  133. }
  134. }
  135. else
  136. {
  137. pGrenade->m_decoyWeaponId = (CSWeaponID)pPrimaryWeapon->GetWeaponID();
  138. }
  139. }
  140. else if ( pSecondaryWeapon != NULL )
  141. {
  142. CEconItemView* pItem = pSecondaryWeapon->GetEconItemView();
  143. if ( pItem && pItem->IsValid() )
  144. {
  145. pGrenade->m_decoyWeaponDefIndex = pItem->GetItemDefinition()->GetDefinitionIndex();
  146. pGrenade->m_decoyWeaponId = WeaponIdFromString( pItem->GetItemDefinition()->GetItemClass() );
  147. CWeaponCSBase *pWeapon = static_cast<CWeaponCSBase *>( pSecondaryWeapon );
  148. if ( pWeapon )
  149. {
  150. pGrenade->m_decoyWeaponSoundType = ( pWeapon->HasSilencer() && pWeapon->IsSilenced() ) ? SPECIAL1 : SINGLE;
  151. }
  152. }
  153. else
  154. {
  155. pGrenade->m_decoyWeaponId = (CSWeaponID)pSecondaryWeapon->GetWeaponID();
  156. }
  157. }
  158. else
  159. {
  160. if ( pOwner->GetTeamNumber() == TEAM_CT )
  161. {
  162. pGrenade->m_decoyWeaponId = WEAPON_HKP2000;
  163. }
  164. else
  165. {
  166. pGrenade->m_decoyWeaponId = WEAPON_GLOCK;
  167. }
  168. }
  169. const CCSWeaponInfo* pDecoyWeaponInfo = GetWeaponInfo(pGrenade->m_decoyWeaponId);
  170. // find the corresponding decoy firing profile
  171. pGrenade->m_pProfile = &gDecoyWeaponProfiles[0];
  172. for ( int i = 0; i < ARRAYSIZE( gDecoyWeaponProfiles ); ++i )
  173. {
  174. if ( gDecoyWeaponProfiles[i].weaponType == pDecoyWeaponInfo->GetWeaponType() )
  175. {
  176. pGrenade->m_pProfile = &gDecoyWeaponProfiles[i];
  177. break;
  178. }
  179. }
  180. pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
  181. return pGrenade;
  182. }
  183. void CDecoyProjectile::SetTimer( float timer )
  184. {
  185. SetThink( &CDecoyProjectile::Think_Detonate );
  186. SetNextThink( gpGlobals->curtime + timer );
  187. TheBots->SetGrenadeRadius( this, 0.0f );
  188. }
  189. void CDecoyProjectile::Think_Detonate( void )
  190. {
  191. #if 1
  192. if ( GetAbsVelocity().Length() > 0.2f )
  193. {
  194. // Still moving. Don't detonate yet.
  195. SetNextThink( gpGlobals->curtime + 0.2f );
  196. return;
  197. }
  198. #endif // 0
  199. CCSPlayer *player = ToCSPlayer( GetThrower() );
  200. if ( player )
  201. {
  202. IGameEvent * event = gameeventmanager->CreateEvent( "decoy_started" );
  203. if ( event )
  204. {
  205. event->SetInt( "userid", player->GetUserID() );
  206. event->SetInt( "entityid", this->entindex() );
  207. event->SetFloat( "x", GetAbsOrigin().x );
  208. event->SetFloat( "y", GetAbsOrigin().y );
  209. event->SetFloat( "z", GetAbsOrigin().z );
  210. gameeventmanager->FireEvent( event );
  211. }
  212. }
  213. m_shotsRemaining = 0;
  214. m_fExpireTime = gpGlobals->curtime + 14.0f; // TODO: Make this Data Driven
  215. SetThink( &CDecoyProjectile::GunfireThink );
  216. TheBots->SetGrenadeRadius( this, DecoyGrenadeRadius );
  217. GunfireThink(); // This will handling the 'Detonate'
  218. }
  219. void CDecoyProjectile::Detonate( void )
  220. {
  221. // [mlowrance] The Decoy is handling it's own detonate.
  222. Assert(!"Decoy grenade handles its own detonation");
  223. }
  224. void CDecoyProjectile::GunfireThink( void )
  225. {
  226. ASSERT(m_pProfile != NULL);
  227. if ( !m_pProfile )
  228. return;
  229. if ( m_shotsRemaining <= 0 )
  230. {
  231. // pick a new burst activity
  232. m_shotsRemaining = RandomInt( m_pProfile->minShots, m_pProfile->maxShots );
  233. }
  234. const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo(m_decoyWeaponId);
  235. CBroadcastRecipientFilter filter;
  236. const char *shootsound = pWeaponInfo->aShootSounds[ m_decoyWeaponSoundType ];
  237. if ( m_decoyWeaponDefIndex != INVALID_ITEM_DEF_INDEX )
  238. {
  239. // Get the item definition
  240. const CEconItemDefinition *pDef = ( m_decoyWeaponDefIndex > 0 ) ? GetItemSchema()->GetItemDefinition( m_decoyWeaponDefIndex ) : NULL;
  241. if ( pDef )
  242. {
  243. const char *pszTempSound = pDef->GetWeaponReplacementSound( m_decoyWeaponSoundType );
  244. if ( pszTempSound )
  245. {
  246. shootsound = pszTempSound;
  247. }
  248. }
  249. }
  250. CSoundParameters params;
  251. if ( GetParametersForSound( shootsound, params, NULL ) )
  252. {
  253. CPASAttenuationFilter filter( this, params.soundlevel );
  254. EmitSound( filter, entindex(), shootsound, &GetLocalOrigin(), 0.0f );
  255. DispatchParticleEffect( "weapon_decoy_ground_effect_shot", GetAbsOrigin(), GetAbsAngles() );
  256. }
  257. // tell the bots about the gunfire
  258. CCSPlayer *pPlayer = ToCSPlayer( GetThrower() );
  259. if ( pPlayer )
  260. {
  261. // allow the bots to react to the "gunfire"
  262. // we need a custom event here, because the "weapon_fire" event assumes
  263. // the gunfire is coming from the player!
  264. IGameEvent * event = gameeventmanager->CreateEvent( "decoy_firing" );
  265. if ( event )
  266. {
  267. event->SetInt( "userid", pPlayer->GetUserID() );
  268. event->SetInt( "entityid", this->entindex() );
  269. event->SetFloat( "x", GetAbsOrigin().x );
  270. event->SetFloat( "y", GetAbsOrigin().y );
  271. event->SetFloat( "z", GetAbsOrigin().z );
  272. gameeventmanager->FireEvent( event );
  273. }
  274. }
  275. if ( --m_shotsRemaining > 0 )
  276. {
  277. SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( 0.0f, m_pProfile->extraDelay) );
  278. return;
  279. }
  280. if ( gpGlobals->curtime < m_fExpireTime )
  281. {
  282. SetNextThink( gpGlobals->curtime + pWeaponInfo->GetCycleTime() + RandomFloat( m_pProfile->pauseMin, m_pProfile->pauseMax ) );
  283. }
  284. else
  285. {
  286. // [mlowrance] Do the damage on Despawn and post event
  287. CCSPlayer *player = ToCSPlayer( GetThrower() );
  288. if ( player )
  289. {
  290. IGameEvent * event = gameeventmanager->CreateEvent( "decoy_detonate" );
  291. if ( event )
  292. {
  293. event->SetInt( "userid", player->GetUserID() );
  294. event->SetInt( "entityid", this->entindex() );
  295. event->SetFloat( "x", GetAbsOrigin().x );
  296. event->SetFloat( "y", GetAbsOrigin().y );
  297. event->SetFloat( "z", GetAbsOrigin().z );
  298. gameeventmanager->FireEvent( event );
  299. }
  300. }
  301. BaseClass::Detonate();
  302. UTIL_Remove( this );
  303. }
  304. }
  305. void CDecoyProjectile::Spawn( void )
  306. {
  307. SetModel( GRENADE_MODEL );
  308. BaseClass::Spawn();
  309. SetBodygroupPreset( "thrown" );
  310. }
  311. void CDecoyProjectile::Precache( void )
  312. {
  313. PrecacheModel( GRENADE_MODEL );
  314. PrecacheScriptSound( "Flashbang.Explode" );
  315. PrecacheScriptSound( "Flashbang.Bounce" );
  316. PrecacheParticleSystem( "weapon_decoy_ground_effect_shot" );
  317. BaseClass::Precache();
  318. }
  319. //TODO: Let physics handle the sound!
  320. void CDecoyProjectile::BounceSound( void )
  321. {
  322. EmitSound( "Flashbang.Bounce" );
  323. }
  324. #endif // GAME_DLL