Team Fortress 2 Source Code as on 22/4/2020
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.

843 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_mg42.h"
  8. #include "engine/ivdebugoverlay.h"
  9. #if defined( CLIENT_DLL )
  10. #include "tier1/KeyValues.h"
  11. #include "particles_simple.h"
  12. #include "particles_localspace.h"
  13. #include "fx.h"
  14. #include "c_dod_player.h"
  15. #else
  16. #include "dod_player.h"
  17. #endif
  18. #ifdef CLIENT_DLL
  19. void ToolFramework_PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg );
  20. #endif
  21. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMG42, DT_WeaponMG42 )
  22. #ifdef GAME_DLL
  23. BEGIN_DATADESC( CWeaponMG42 )
  24. DEFINE_THINKFUNC( CoolThink ),
  25. END_DATADESC()
  26. #endif
  27. BEGIN_NETWORK_TABLE( CWeaponMG42, DT_WeaponMG42 )
  28. #ifdef CLIENT_DLL
  29. RecvPropInt ( RECVINFO( m_iWeaponHeat ) ),
  30. RecvPropTime ( RECVINFO( m_flNextCoolTime ) ),
  31. RecvPropBool ( RECVINFO( m_bOverheated ) ),
  32. #else
  33. SendPropInt ( SENDINFO( m_iWeaponHeat ), 7, SPROP_UNSIGNED ),
  34. SendPropFloat ( SENDINFO( m_flNextCoolTime ) ),
  35. SendPropBool ( SENDINFO( m_bOverheated ) ),
  36. #endif
  37. END_NETWORK_TABLE()
  38. #ifdef CLIENT_DLL
  39. BEGIN_PREDICTION_DATA( CWeaponMG42 )
  40. DEFINE_PRED_FIELD( m_iWeaponHeat, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  41. DEFINE_PRED_FIELD_TOL( m_flNextCoolTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  42. DEFINE_PRED_FIELD( m_bOverheated, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  43. END_PREDICTION_DATA()
  44. #endif
  45. LINK_ENTITY_TO_CLASS( weapon_mg42, CWeaponMG42 );
  46. PRECACHE_WEAPON_REGISTER( weapon_mg42 );
  47. acttable_t CWeaponMG42::m_acttable[] =
  48. {
  49. { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_MG, false },
  50. { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_MG, false },
  51. { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_MG, false },
  52. { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_MG, false },
  53. { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_MG, false },
  54. { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MG, false },
  55. { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_MG, false },
  56. { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_MG, false },
  57. { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_MG, false },
  58. { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_MG, false },
  59. { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_MG, false },
  60. { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_MG, false },
  61. { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_MG, false },
  62. // Deployed Aim
  63. { ACT_DOD_DEPLOYED, ACT_DOD_DEPLOY_MG, false },
  64. { ACT_DOD_PRONE_DEPLOYED, ACT_DOD_PRONE_DEPLOY_MG, false },
  65. // Attack ( prone? deployed? )
  66. { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MG, false },
  67. { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_MG, false },
  68. { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MG, false },
  69. { ACT_DOD_PRIMARYATTACK_DEPLOYED, ACT_DOD_PRIMARYATTACK_DEPLOYED_MG, false },
  70. { ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_MG,false },
  71. // Reload ( prone? deployed? )
  72. { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_RELOAD_DEPLOYED_MG, false },
  73. { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_RELOAD_PRONE_DEPLOYED_MG, false },
  74. // Hand Signals
  75. { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MG42, false },
  76. { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MG42, false },
  77. };
  78. IMPLEMENT_ACTTABLE( CWeaponMG42 );
  79. void CWeaponMG42::Spawn( void )
  80. {
  81. m_iWeaponHeat = 0;
  82. m_flNextCoolTime = 0;
  83. m_bOverheated = false;
  84. #ifdef CLIENT_DLL
  85. m_pEmitter = NULL;
  86. m_flParticleAccumulator = 0.0;
  87. m_hParticleMaterial = ParticleMgr()->GetPMaterial( "sprites/effects/bazookapuff" );
  88. #endif
  89. BaseClass::Spawn();
  90. }
  91. #ifdef CLIENT_DLL
  92. CWeaponMG42::~CWeaponMG42()
  93. {
  94. if ( clienttools->IsInRecordingMode() && m_pEmitter.IsValid() && m_pEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID )
  95. {
  96. KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" );
  97. msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() );
  98. msg->SetFloat( "time", gpGlobals->curtime );
  99. msg->SetInt( "active", 0 );
  100. msg->SetInt( "emitter", 0 );
  101. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  102. msg->SetInt( "emitter", 1 );
  103. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  104. msg->SetInt( "emitter", 2 );
  105. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  106. msg->SetInt( "emitter", 3 );
  107. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  108. msg->deleteThis();
  109. }
  110. }
  111. void CWeaponMG42::OnDataChanged( DataUpdateType_t updateType )
  112. {
  113. BaseClass::OnDataChanged( updateType );
  114. // BUG! This can happen more than once!
  115. if ( updateType == DATA_UPDATE_CREATED )
  116. {
  117. if ( !m_pEmitter.IsValid() )
  118. {
  119. m_pEmitter = CSimpleEmitter::Create( "MGOverheat" );
  120. }
  121. Assert( m_pEmitter.IsValid() );
  122. }
  123. ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
  124. }
  125. // Client Think emits smoke particles based on heat
  126. // ( except if we are holstered )
  127. void CWeaponMG42::ClientThink( void )
  128. {
  129. m_pEmitter->SetSortOrigin( GetAbsOrigin() );
  130. float flEmitRate = 0.0; //particles per second
  131. // Only smoke if we are dropped ( no owner ) or if we have an owner and are active
  132. if ( GetOwner() == NULL || GetOwner()->GetActiveWeapon() == this )
  133. {
  134. if ( m_iWeaponHeat > 85 )
  135. {
  136. flEmitRate = 30;
  137. }
  138. else if ( m_iWeaponHeat > 80 )
  139. {
  140. flEmitRate = 20;
  141. }
  142. else if ( m_iWeaponHeat > 65 )
  143. {
  144. flEmitRate = 10;
  145. }
  146. else if ( m_iWeaponHeat > 50 )
  147. {
  148. flEmitRate = 5;
  149. }
  150. }
  151. m_flParticleAccumulator += ( gpGlobals->frametime * flEmitRate );
  152. while( m_flParticleAccumulator > 0.0 )
  153. {
  154. EmitSmokeParticle();
  155. m_flParticleAccumulator -= 1.0;
  156. }
  157. }
  158. void CWeaponMG42::EmitSmokeParticle( void )
  159. {
  160. Vector vFront, vBack;
  161. QAngle angles;
  162. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  163. bool bViewModel = false;
  164. // if this is locally owned
  165. if ( GetPlayerOwner() == pLocalPlayer )
  166. {
  167. C_BaseViewModel *vm = pLocalPlayer->GetViewModel( 0 );
  168. if ( !vm )
  169. return;
  170. vm->GetAttachment( 1, vFront, angles );
  171. vm->GetAttachment( 2, vBack, angles );
  172. bViewModel = true;
  173. }
  174. else
  175. {
  176. // could be dropped, or held by another player
  177. GetAttachment( 1, vFront, angles );
  178. GetAttachment( 2, vBack, angles );
  179. }
  180. // Get a position somewhere on the barrel
  181. Vector vPos = vBack + random->RandomFloat(0.0, 1.0 ) * ( vFront - vBack );
  182. SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos );
  183. if ( pParticle )
  184. {
  185. pParticle->m_vecVelocity = Vector( 0,0,12 );
  186. pParticle->m_flRoll = random->RandomFloat( 0, 0.5 );
  187. pParticle->m_flRollDelta = ( random->RandomInt(0,1) == 0 ? 1 : -1 ) * random->RandomFloat( 0.5, 1.0 );
  188. pParticle->m_flDieTime = 1.8f;
  189. pParticle->m_flLifetime = 0;
  190. pParticle->m_uchColor[0] = 200;
  191. pParticle->m_uchColor[1] = 200;
  192. pParticle->m_uchColor[2] = 200;
  193. pParticle->m_uchStartAlpha = 60;
  194. pParticle->m_uchEndAlpha = 0;
  195. pParticle->m_uchStartSize = 4;
  196. pParticle->m_uchEndSize = 25;
  197. pParticle->m_iFlags = 0; //bViewModel ? FLE_VIEWMODEL : 0;
  198. }
  199. }
  200. #else
  201. // This function does the cooling when the weapon is dropped or holstered
  202. // regular, predicted cooling is done in ItemPostFrame
  203. void CWeaponMG42::CoolThink( void )
  204. {
  205. if ( m_iWeaponHeat > 0 )
  206. m_iWeaponHeat--;
  207. SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
  208. }
  209. #endif
  210. void CWeaponMG42::Precache()
  211. {
  212. PrecacheMaterial( "sprites/effects/bazookapuff" );
  213. PrecacheScriptSound( "Weapon_Mg42.OverHeat" );
  214. BaseClass::Precache();
  215. }
  216. bool CWeaponMG42::Reload( void )
  217. {
  218. if( !IsDeployed() )
  219. {
  220. #ifdef CLIENT_DLL
  221. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  222. if ( pPlayer )
  223. pPlayer->HintMessage( HINT_MG_DEPLOY_TO_RELOAD );
  224. #endif
  225. return false;
  226. }
  227. return BaseClass::Reload();
  228. }
  229. void CWeaponMG42::FinishReload( void )
  230. {
  231. BaseClass::FinishReload();
  232. //Reset the heat when you complete a reload
  233. m_iWeaponHeat = 0;
  234. }
  235. void CWeaponMG42::PrimaryAttack( void )
  236. {
  237. if( m_bOverheated )
  238. {
  239. return;
  240. }
  241. if ( m_iClip1 <= 0 )
  242. {
  243. if (m_bFireOnEmpty)
  244. {
  245. PlayEmptySound();
  246. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  247. }
  248. return;
  249. }
  250. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  251. Assert( pPlayer );
  252. if( m_iWeaponHeat >= 99 )
  253. {
  254. //can't fire anymore, wait until heat is below 80
  255. #ifdef CLIENT_DLL
  256. pPlayer->HintMessage( HINT_WEAPON_OVERHEAT );
  257. #endif
  258. m_bOverheated = true;
  259. m_bInAttack = true;
  260. EmitSound( "Weapon_Mg42.OverHeat" );
  261. return;
  262. }
  263. m_iWeaponHeat += 1; //2;
  264. m_flNextCoolTime = gpGlobals->curtime + 0.16f;
  265. if( !IsDeployed() )
  266. {
  267. #ifdef CLIENT_DLL
  268. pPlayer->HintMessage( HINT_MG_FIRE_UNDEPLOYED );
  269. #endif
  270. pPlayer->m_Shared.SetSlowedTime( 0.2 );
  271. float flStamina = pPlayer->m_Shared.GetStamina();
  272. pPlayer->m_Shared.SetStamina( flStamina - 15 );
  273. }
  274. BaseClass::PrimaryAttack();
  275. }
  276. void CWeaponMG42::ItemPostFrame( void )
  277. {
  278. ItemFrameCool();
  279. if( m_iWeaponHeat < 80 )
  280. m_bOverheated = false;
  281. BaseClass::ItemPostFrame();
  282. }
  283. void CWeaponMG42::ItemBusyFrame( void )
  284. {
  285. ItemFrameCool();
  286. BaseClass::ItemBusyFrame();
  287. }
  288. void CWeaponMG42::ItemFrameCool( void )
  289. {
  290. if( gpGlobals->curtime > m_flNextCoolTime )
  291. {
  292. if ( m_iWeaponHeat > 0 )
  293. m_iWeaponHeat--;
  294. m_flNextCoolTime = gpGlobals->curtime + 0.16f;
  295. }
  296. }
  297. bool CWeaponMG42::Deploy( void )
  298. {
  299. // stop the fake cooling when we deploy the weapon
  300. SetContextThink( NULL, 0.0, COOL_CONTEXT );
  301. return BaseClass::Deploy();
  302. }
  303. bool CWeaponMG42::Holster( CBaseCombatWeapon *pSwitchingTo )
  304. {
  305. #ifndef CLIENT_DLL
  306. SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
  307. #endif
  308. return BaseClass::Holster(pSwitchingTo);
  309. }
  310. void CWeaponMG42::Drop( const Vector &vecVelocity )
  311. {
  312. #ifndef CLIENT_DLL
  313. SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT );
  314. #endif
  315. BaseClass::Drop( vecVelocity );
  316. }
  317. Activity CWeaponMG42::GetReloadActivity( void )
  318. {
  319. return ACT_VM_RELOAD;
  320. }
  321. Activity CWeaponMG42::GetDrawActivity( void )
  322. {
  323. Activity actDraw;
  324. if( 0 && m_iClip1 <= 0 )
  325. actDraw = ACT_VM_DRAW_EMPTY;
  326. else
  327. actDraw = ACT_VM_DRAW;
  328. return actDraw;
  329. }
  330. Activity CWeaponMG42::GetDeployActivity( void )
  331. {
  332. Activity actDeploy;
  333. switch ( m_iClip1 )
  334. {
  335. case 8:
  336. actDeploy = ACT_VM_DEPLOY_8;
  337. break;
  338. case 7:
  339. actDeploy = ACT_VM_DEPLOY_7;
  340. break;
  341. case 6:
  342. actDeploy = ACT_VM_DEPLOY_6;
  343. break;
  344. case 5:
  345. actDeploy = ACT_VM_DEPLOY_5;
  346. break;
  347. case 4:
  348. actDeploy = ACT_VM_DEPLOY_4;
  349. break;
  350. case 3:
  351. actDeploy = ACT_VM_DEPLOY_3;
  352. break;
  353. case 2:
  354. actDeploy = ACT_VM_DEPLOY_2;
  355. break;
  356. case 1:
  357. actDeploy = ACT_VM_DEPLOY_1;
  358. break;
  359. case 0:
  360. actDeploy = ACT_VM_DEPLOY_EMPTY;
  361. break;
  362. default:
  363. actDeploy = ACT_VM_DEPLOY;
  364. break;
  365. }
  366. return actDeploy;
  367. }
  368. Activity CWeaponMG42::GetUndeployActivity( void )
  369. {
  370. Activity actUndeploy;
  371. switch ( m_iClip1 )
  372. {
  373. case 8:
  374. actUndeploy = ACT_VM_UNDEPLOY_8;
  375. break;
  376. case 7:
  377. actUndeploy = ACT_VM_UNDEPLOY_7;
  378. break;
  379. case 6:
  380. actUndeploy = ACT_VM_UNDEPLOY_6;
  381. break;
  382. case 5:
  383. actUndeploy = ACT_VM_UNDEPLOY_5;
  384. break;
  385. case 4:
  386. actUndeploy = ACT_VM_UNDEPLOY_4;
  387. break;
  388. case 3:
  389. actUndeploy = ACT_VM_UNDEPLOY_3;
  390. break;
  391. case 2:
  392. actUndeploy = ACT_VM_UNDEPLOY_2;
  393. break;
  394. case 1:
  395. actUndeploy = ACT_VM_UNDEPLOY_1;
  396. break;
  397. case 0:
  398. actUndeploy = ACT_VM_UNDEPLOY_EMPTY;
  399. break;
  400. default:
  401. actUndeploy = ACT_VM_UNDEPLOY;
  402. break;
  403. }
  404. return actUndeploy;
  405. }
  406. Activity CWeaponMG42::GetIdleActivity( void )
  407. {
  408. Activity actIdle;
  409. if( IsDeployed() )
  410. {
  411. switch ( m_iClip1 )
  412. {
  413. case 8:
  414. actIdle = ACT_VM_IDLE_DEPLOYED_8;
  415. break;
  416. case 7:
  417. actIdle = ACT_VM_IDLE_DEPLOYED_7;
  418. break;
  419. case 6:
  420. actIdle = ACT_VM_IDLE_DEPLOYED_6;
  421. break;
  422. case 5:
  423. actIdle = ACT_VM_IDLE_DEPLOYED_5;
  424. break;
  425. case 4:
  426. actIdle = ACT_VM_IDLE_DEPLOYED_4;
  427. break;
  428. case 3:
  429. actIdle = ACT_VM_IDLE_DEPLOYED_3;
  430. break;
  431. case 2:
  432. actIdle = ACT_VM_IDLE_DEPLOYED_2;
  433. break;
  434. case 1:
  435. actIdle = ACT_VM_IDLE_DEPLOYED_1;
  436. break;
  437. case 0:
  438. actIdle = ACT_VM_IDLE_DEPLOYED_EMPTY;
  439. break;
  440. default:
  441. actIdle = ACT_VM_IDLE_DEPLOYED;
  442. break;
  443. }
  444. }
  445. else
  446. {
  447. switch ( m_iClip1 )
  448. {
  449. case 8:
  450. actIdle = ACT_VM_IDLE_8;
  451. break;
  452. case 7:
  453. actIdle = ACT_VM_IDLE_7;
  454. break;
  455. case 6:
  456. actIdle = ACT_VM_IDLE_6;
  457. break;
  458. case 5:
  459. actIdle = ACT_VM_IDLE_5;
  460. break;
  461. case 4:
  462. actIdle = ACT_VM_IDLE_4;
  463. break;
  464. case 3:
  465. actIdle = ACT_VM_IDLE_3;
  466. break;
  467. case 2:
  468. actIdle = ACT_VM_IDLE_2;
  469. break;
  470. case 1:
  471. actIdle = ACT_VM_IDLE_1;
  472. break;
  473. case 0:
  474. actIdle = ACT_VM_IDLE_EMPTY;
  475. break;
  476. default:
  477. actIdle = ACT_VM_IDLE;
  478. break;
  479. }
  480. }
  481. return actIdle;
  482. }
  483. Activity CWeaponMG42::GetPrimaryAttackActivity( void )
  484. {
  485. Activity actPrim;
  486. if( IsDeployed() )
  487. {
  488. switch ( m_iClip1 )
  489. {
  490. case 8:
  491. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_8;
  492. break;
  493. case 7:
  494. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_7;
  495. break;
  496. case 6:
  497. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_6;
  498. break;
  499. case 5:
  500. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_5;
  501. break;
  502. case 4:
  503. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_4;
  504. break;
  505. case 3:
  506. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_3;
  507. break;
  508. case 2:
  509. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_2;
  510. break;
  511. case 1:
  512. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_1;
  513. break;
  514. case 0:
  515. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY;
  516. break;
  517. default:
  518. actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED;
  519. break;
  520. }
  521. }
  522. else
  523. {
  524. switch ( m_iClip1 )
  525. {
  526. case 8:
  527. actPrim = ACT_VM_PRIMARYATTACK_8;
  528. break;
  529. case 7:
  530. actPrim = ACT_VM_PRIMARYATTACK_7;
  531. break;
  532. case 6:
  533. actPrim = ACT_VM_PRIMARYATTACK_6;
  534. break;
  535. case 5:
  536. actPrim = ACT_VM_PRIMARYATTACK_5;
  537. break;
  538. case 4:
  539. actPrim = ACT_VM_PRIMARYATTACK_4;
  540. break;
  541. case 3:
  542. actPrim = ACT_VM_PRIMARYATTACK_3;
  543. break;
  544. case 2:
  545. actPrim = ACT_VM_PRIMARYATTACK_2;
  546. break;
  547. case 1:
  548. actPrim = ACT_VM_PRIMARYATTACK_1;
  549. break;
  550. case 0:
  551. actPrim = ACT_VM_PRIMARYATTACK_EMPTY;
  552. break;
  553. default:
  554. actPrim = ACT_VM_PRIMARYATTACK;
  555. break;
  556. }
  557. }
  558. return actPrim;
  559. }
  560. float CWeaponMG42::GetRecoil( void )
  561. {
  562. CDODPlayer *p = ToDODPlayer( GetPlayerOwner() );
  563. if( p && p->m_Shared.IsInMGDeploy() )
  564. {
  565. return 0.0f;
  566. }
  567. return 20;
  568. }
  569. #ifdef CLIENT_DLL
  570. //-----------------------------------------------------------------------------
  571. // This is called after sending this entity's recording state
  572. //-----------------------------------------------------------------------------
  573. void CWeaponMG42::CleanupToolRecordingState( KeyValues *msg )
  574. {
  575. BaseClass::CleanupToolRecordingState( msg );
  576. // Generally, this is used to allow the entity to clean up
  577. // allocated state it put into the message, but here we're going
  578. // to use it to send particle system messages because we
  579. // know the smoke has been recorded at this point
  580. if ( !clienttools->IsInRecordingMode() || !m_pEmitter.IsValid() )
  581. return;
  582. // NOTE: Particle system destruction message will be sent by the particle effect itself.
  583. if ( m_pEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID )
  584. {
  585. int nId = m_pEmitter->AllocateToolParticleEffectId();
  586. KeyValues *msg = new KeyValues( "ParticleSystem_Create" );
  587. msg->SetString( "name", "CWeaponMG42 smoke" );
  588. msg->SetInt( "id", nId );
  589. msg->SetFloat( "time", gpGlobals->curtime );
  590. KeyValues *pEmitter0 = msg->FindKey( "DmeSpriteEmitter", true );
  591. pEmitter0->SetInt( "count", 5 ); // particles per second, when duration is < 0
  592. pEmitter0->SetFloat( "duration", -1 );
  593. pEmitter0->SetString( "material", "sprites/effects/bazookapuff" );
  594. pEmitter0->SetInt( "active", 0 );
  595. KeyValues *pInitializers = pEmitter0->FindKey( "initializers", true );
  596. KeyValues *pPosition = pInitializers->FindKey( "DmeRandomAttachmentPositionEntityInitializer", true );
  597. pPosition->SetPtr( "entindex", (void*)entindex() );
  598. pPosition->SetInt( "attachmentIndex0", 1 );
  599. pPosition->SetInt( "attachmentIndex1", 2 );
  600. KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
  601. pLifetime->SetFloat( "minLifetime", 1.8f );
  602. pLifetime->SetFloat( "maxLifetime", 1.8f );
  603. KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
  604. pVelocity->SetFloat( "velocityX", 0.0f );
  605. pVelocity->SetFloat( "velocityY", 0.0f );
  606. pVelocity->SetFloat( "velocityZ", 12.0f );
  607. KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
  608. pRoll->SetFloat( "minRoll", 0.0f );
  609. pRoll->SetFloat( "maxRoll", 0.5f );
  610. KeyValues *pRollSpeed = pInitializers->FindKey( "DmeSplitRandomRollSpeedInitializer", true );
  611. pRollSpeed->SetFloat( "minRollSpeed", 0.5f );
  612. pRollSpeed->SetFloat( "maxRollSpeed", 1.0f );
  613. KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
  614. pColor->SetColor( "color1", Color( 200, 200, 200, 255 ) );
  615. pColor->SetColor( "color2", Color( 200, 200, 200, 255 ) );
  616. KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
  617. pAlpha->SetInt( "minStartAlpha", 60 );
  618. pAlpha->SetInt( "maxStartAlpha", 60 );
  619. pAlpha->SetInt( "minEndAlpha", 0 );
  620. pAlpha->SetInt( "maxEndAlpha", 0 );
  621. KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true );
  622. pSize->SetFloat( "minStartSize", 4 );
  623. pSize->SetFloat( "maxStartSize", 4 );
  624. pSize->SetFloat( "minEndSize", 25 );
  625. pSize->SetFloat( "maxEndSize", 25 );
  626. KeyValues *pUpdaters = pEmitter0->FindKey( "updaters", true );
  627. pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
  628. pUpdaters->FindKey( "DmeRollUpdater", true );
  629. pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
  630. pUpdaters->FindKey( "DmeSizeUpdater", true );
  631. // create emitters for each emission rate: 5,10,20,30
  632. KeyValues *pEmitter1 = pEmitter0->MakeCopy();
  633. pEmitter1->SetInt( "count", 10 );
  634. msg->AddSubKey( pEmitter1 );
  635. KeyValues *pEmitter2 = pEmitter0->MakeCopy();
  636. pEmitter2->SetInt( "count", 20 );
  637. msg->AddSubKey( pEmitter2 );
  638. KeyValues *pEmitter3 = pEmitter0->MakeCopy();
  639. pEmitter3->SetInt( "count", 30 );
  640. msg->AddSubKey( pEmitter3 );
  641. // mark only the appropriate emitter active
  642. bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this;
  643. if ( !bHolstered )
  644. {
  645. if ( m_iWeaponHeat > 85 )
  646. {
  647. pEmitter3->SetInt( "active", 1 );
  648. }
  649. else if ( m_iWeaponHeat > 80 )
  650. {
  651. pEmitter2->SetInt( "active", 1 );
  652. }
  653. else if ( m_iWeaponHeat > 65 )
  654. {
  655. pEmitter1->SetInt( "active", 1 );
  656. }
  657. else if ( m_iWeaponHeat > 50 )
  658. {
  659. pEmitter0->SetInt( "active", 1 );
  660. }
  661. }
  662. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  663. msg->deleteThis();
  664. }
  665. else
  666. {
  667. int nEmitterIndex = -1;
  668. bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this;
  669. if ( !bHolstered )
  670. {
  671. if ( m_iWeaponHeat > 85 )
  672. {
  673. nEmitterIndex = 3;
  674. }
  675. else if ( m_iWeaponHeat > 80 )
  676. {
  677. nEmitterIndex = 2;
  678. }
  679. else if ( m_iWeaponHeat > 65 )
  680. {
  681. nEmitterIndex = 1;
  682. }
  683. else if ( m_iWeaponHeat > 50 )
  684. {
  685. nEmitterIndex = 0;
  686. }
  687. }
  688. KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" );
  689. msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() );
  690. msg->SetFloat( "time", gpGlobals->curtime );
  691. msg->SetInt( "emitter", 0 );
  692. msg->SetInt( "active", nEmitterIndex == 0 );
  693. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  694. msg->SetInt( "emitter", 1 );
  695. msg->SetInt( "active", nEmitterIndex == 1 );
  696. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  697. msg->SetInt( "emitter", 2 );
  698. msg->SetInt( "active", nEmitterIndex == 2 );
  699. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  700. msg->SetInt( "emitter", 3 );
  701. msg->SetInt( "active", nEmitterIndex == 3 );
  702. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  703. msg->deleteThis();
  704. }
  705. }
  706. #endif