//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "weapon_mg42.h" #include "engine/ivdebugoverlay.h" #if defined( CLIENT_DLL ) #include "tier1/KeyValues.h" #include "particles_simple.h" #include "particles_localspace.h" #include "fx.h" #include "c_dod_player.h" #else #include "dod_player.h" #endif #ifdef CLIENT_DLL void ToolFramework_PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ); #endif IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMG42, DT_WeaponMG42 ) #ifdef GAME_DLL BEGIN_DATADESC( CWeaponMG42 ) DEFINE_THINKFUNC( CoolThink ), END_DATADESC() #endif BEGIN_NETWORK_TABLE( CWeaponMG42, DT_WeaponMG42 ) #ifdef CLIENT_DLL RecvPropInt ( RECVINFO( m_iWeaponHeat ) ), RecvPropTime ( RECVINFO( m_flNextCoolTime ) ), RecvPropBool ( RECVINFO( m_bOverheated ) ), #else SendPropInt ( SENDINFO( m_iWeaponHeat ), 7, SPROP_UNSIGNED ), SendPropFloat ( SENDINFO( m_flNextCoolTime ) ), SendPropBool ( SENDINFO( m_bOverheated ) ), #endif END_NETWORK_TABLE() #ifdef CLIENT_DLL BEGIN_PREDICTION_DATA( CWeaponMG42 ) DEFINE_PRED_FIELD( m_iWeaponHeat, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD_TOL( m_flNextCoolTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ), DEFINE_PRED_FIELD( m_bOverheated, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), END_PREDICTION_DATA() #endif LINK_ENTITY_TO_CLASS( weapon_mg42, CWeaponMG42 ); PRECACHE_WEAPON_REGISTER( weapon_mg42 ); acttable_t CWeaponMG42::m_acttable[] = { { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_MG, false }, { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_MG, false }, { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_MG, false }, { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_MG, false }, { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_MG, false }, { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_MG, false }, { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_IDLE_MG, false }, { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_IDLE_MG, false }, { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_MG, false }, { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_IDLE_MG, false }, { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_IDLE_MG, false }, { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_IDLE_MG, false }, { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_MG, false }, // Deployed Aim { ACT_DOD_DEPLOYED, ACT_DOD_DEPLOY_MG, false }, { ACT_DOD_PRONE_DEPLOYED, ACT_DOD_PRONE_DEPLOY_MG, false }, // Attack ( prone? deployed? ) { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_MG, false }, { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_MG, false }, { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_MG, false }, { ACT_DOD_PRIMARYATTACK_DEPLOYED, ACT_DOD_PRIMARYATTACK_DEPLOYED_MG, false }, { ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED, ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED_MG,false }, // Reload ( prone? deployed? ) { ACT_DOD_RELOAD_DEPLOYED, ACT_DOD_RELOAD_DEPLOYED_MG, false }, { ACT_DOD_RELOAD_PRONE_DEPLOYED, ACT_DOD_RELOAD_PRONE_DEPLOYED_MG, false }, // Hand Signals { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_MG42, false }, { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_MG42, false }, }; IMPLEMENT_ACTTABLE( CWeaponMG42 ); void CWeaponMG42::Spawn( void ) { m_iWeaponHeat = 0; m_flNextCoolTime = 0; m_bOverheated = false; #ifdef CLIENT_DLL m_pEmitter = NULL; m_flParticleAccumulator = 0.0; m_hParticleMaterial = ParticleMgr()->GetPMaterial( "sprites/effects/bazookapuff" ); #endif BaseClass::Spawn(); } #ifdef CLIENT_DLL CWeaponMG42::~CWeaponMG42() { if ( clienttools->IsInRecordingMode() && m_pEmitter.IsValid() && m_pEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID ) { KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" ); msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() ); msg->SetFloat( "time", gpGlobals->curtime ); msg->SetInt( "active", 0 ); msg->SetInt( "emitter", 0 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 1 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 2 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 3 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); } } void CWeaponMG42::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); // BUG! This can happen more than once! if ( updateType == DATA_UPDATE_CREATED ) { if ( !m_pEmitter.IsValid() ) { m_pEmitter = CSimpleEmitter::Create( "MGOverheat" ); } Assert( m_pEmitter.IsValid() ); } ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); } // Client Think emits smoke particles based on heat // ( except if we are holstered ) void CWeaponMG42::ClientThink( void ) { m_pEmitter->SetSortOrigin( GetAbsOrigin() ); float flEmitRate = 0.0; //particles per second // Only smoke if we are dropped ( no owner ) or if we have an owner and are active if ( GetOwner() == NULL || GetOwner()->GetActiveWeapon() == this ) { if ( m_iWeaponHeat > 85 ) { flEmitRate = 30; } else if ( m_iWeaponHeat > 80 ) { flEmitRate = 20; } else if ( m_iWeaponHeat > 65 ) { flEmitRate = 10; } else if ( m_iWeaponHeat > 50 ) { flEmitRate = 5; } } m_flParticleAccumulator += ( gpGlobals->frametime * flEmitRate ); while( m_flParticleAccumulator > 0.0 ) { EmitSmokeParticle(); m_flParticleAccumulator -= 1.0; } } void CWeaponMG42::EmitSmokeParticle( void ) { Vector vFront, vBack; QAngle angles; C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); bool bViewModel = false; // if this is locally owned if ( GetPlayerOwner() == pLocalPlayer ) { C_BaseViewModel *vm = pLocalPlayer->GetViewModel( 0 ); if ( !vm ) return; vm->GetAttachment( 1, vFront, angles ); vm->GetAttachment( 2, vBack, angles ); bViewModel = true; } else { // could be dropped, or held by another player GetAttachment( 1, vFront, angles ); GetAttachment( 2, vBack, angles ); } // Get a position somewhere on the barrel Vector vPos = vBack + random->RandomFloat(0.0, 1.0 ) * ( vFront - vBack ); SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos ); if ( pParticle ) { pParticle->m_vecVelocity = Vector( 0,0,12 ); pParticle->m_flRoll = random->RandomFloat( 0, 0.5 ); pParticle->m_flRollDelta = ( random->RandomInt(0,1) == 0 ? 1 : -1 ) * random->RandomFloat( 0.5, 1.0 ); pParticle->m_flDieTime = 1.8f; pParticle->m_flLifetime = 0; pParticle->m_uchColor[0] = 200; pParticle->m_uchColor[1] = 200; pParticle->m_uchColor[2] = 200; pParticle->m_uchStartAlpha = 60; pParticle->m_uchEndAlpha = 0; pParticle->m_uchStartSize = 4; pParticle->m_uchEndSize = 25; pParticle->m_iFlags = 0; //bViewModel ? FLE_VIEWMODEL : 0; } } #else // This function does the cooling when the weapon is dropped or holstered // regular, predicted cooling is done in ItemPostFrame void CWeaponMG42::CoolThink( void ) { if ( m_iWeaponHeat > 0 ) m_iWeaponHeat--; SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT ); } #endif void CWeaponMG42::Precache() { PrecacheMaterial( "sprites/effects/bazookapuff" ); PrecacheScriptSound( "Weapon_Mg42.OverHeat" ); BaseClass::Precache(); } bool CWeaponMG42::Reload( void ) { if( !IsDeployed() ) { #ifdef CLIENT_DLL CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); if ( pPlayer ) pPlayer->HintMessage( HINT_MG_DEPLOY_TO_RELOAD ); #endif return false; } return BaseClass::Reload(); } void CWeaponMG42::FinishReload( void ) { BaseClass::FinishReload(); //Reset the heat when you complete a reload m_iWeaponHeat = 0; } void CWeaponMG42::PrimaryAttack( void ) { if( m_bOverheated ) { return; } if ( m_iClip1 <= 0 ) { if (m_bFireOnEmpty) { PlayEmptySound(); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; } return; } CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); Assert( pPlayer ); if( m_iWeaponHeat >= 99 ) { //can't fire anymore, wait until heat is below 80 #ifdef CLIENT_DLL pPlayer->HintMessage( HINT_WEAPON_OVERHEAT ); #endif m_bOverheated = true; m_bInAttack = true; EmitSound( "Weapon_Mg42.OverHeat" ); return; } m_iWeaponHeat += 1; //2; m_flNextCoolTime = gpGlobals->curtime + 0.16f; if( !IsDeployed() ) { #ifdef CLIENT_DLL pPlayer->HintMessage( HINT_MG_FIRE_UNDEPLOYED ); #endif pPlayer->m_Shared.SetSlowedTime( 0.2 ); float flStamina = pPlayer->m_Shared.GetStamina(); pPlayer->m_Shared.SetStamina( flStamina - 15 ); } BaseClass::PrimaryAttack(); } void CWeaponMG42::ItemPostFrame( void ) { ItemFrameCool(); if( m_iWeaponHeat < 80 ) m_bOverheated = false; BaseClass::ItemPostFrame(); } void CWeaponMG42::ItemBusyFrame( void ) { ItemFrameCool(); BaseClass::ItemBusyFrame(); } void CWeaponMG42::ItemFrameCool( void ) { if( gpGlobals->curtime > m_flNextCoolTime ) { if ( m_iWeaponHeat > 0 ) m_iWeaponHeat--; m_flNextCoolTime = gpGlobals->curtime + 0.16f; } } bool CWeaponMG42::Deploy( void ) { // stop the fake cooling when we deploy the weapon SetContextThink( NULL, 0.0, COOL_CONTEXT ); return BaseClass::Deploy(); } bool CWeaponMG42::Holster( CBaseCombatWeapon *pSwitchingTo ) { #ifndef CLIENT_DLL SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT ); #endif return BaseClass::Holster(pSwitchingTo); } void CWeaponMG42::Drop( const Vector &vecVelocity ) { #ifndef CLIENT_DLL SetContextThink( &CWeaponMG42::CoolThink, gpGlobals->curtime + 0.1, COOL_CONTEXT ); #endif BaseClass::Drop( vecVelocity ); } Activity CWeaponMG42::GetReloadActivity( void ) { return ACT_VM_RELOAD; } Activity CWeaponMG42::GetDrawActivity( void ) { Activity actDraw; if( 0 && m_iClip1 <= 0 ) actDraw = ACT_VM_DRAW_EMPTY; else actDraw = ACT_VM_DRAW; return actDraw; } Activity CWeaponMG42::GetDeployActivity( void ) { Activity actDeploy; switch ( m_iClip1 ) { case 8: actDeploy = ACT_VM_DEPLOY_8; break; case 7: actDeploy = ACT_VM_DEPLOY_7; break; case 6: actDeploy = ACT_VM_DEPLOY_6; break; case 5: actDeploy = ACT_VM_DEPLOY_5; break; case 4: actDeploy = ACT_VM_DEPLOY_4; break; case 3: actDeploy = ACT_VM_DEPLOY_3; break; case 2: actDeploy = ACT_VM_DEPLOY_2; break; case 1: actDeploy = ACT_VM_DEPLOY_1; break; case 0: actDeploy = ACT_VM_DEPLOY_EMPTY; break; default: actDeploy = ACT_VM_DEPLOY; break; } return actDeploy; } Activity CWeaponMG42::GetUndeployActivity( void ) { Activity actUndeploy; switch ( m_iClip1 ) { case 8: actUndeploy = ACT_VM_UNDEPLOY_8; break; case 7: actUndeploy = ACT_VM_UNDEPLOY_7; break; case 6: actUndeploy = ACT_VM_UNDEPLOY_6; break; case 5: actUndeploy = ACT_VM_UNDEPLOY_5; break; case 4: actUndeploy = ACT_VM_UNDEPLOY_4; break; case 3: actUndeploy = ACT_VM_UNDEPLOY_3; break; case 2: actUndeploy = ACT_VM_UNDEPLOY_2; break; case 1: actUndeploy = ACT_VM_UNDEPLOY_1; break; case 0: actUndeploy = ACT_VM_UNDEPLOY_EMPTY; break; default: actUndeploy = ACT_VM_UNDEPLOY; break; } return actUndeploy; } Activity CWeaponMG42::GetIdleActivity( void ) { Activity actIdle; if( IsDeployed() ) { switch ( m_iClip1 ) { case 8: actIdle = ACT_VM_IDLE_DEPLOYED_8; break; case 7: actIdle = ACT_VM_IDLE_DEPLOYED_7; break; case 6: actIdle = ACT_VM_IDLE_DEPLOYED_6; break; case 5: actIdle = ACT_VM_IDLE_DEPLOYED_5; break; case 4: actIdle = ACT_VM_IDLE_DEPLOYED_4; break; case 3: actIdle = ACT_VM_IDLE_DEPLOYED_3; break; case 2: actIdle = ACT_VM_IDLE_DEPLOYED_2; break; case 1: actIdle = ACT_VM_IDLE_DEPLOYED_1; break; case 0: actIdle = ACT_VM_IDLE_DEPLOYED_EMPTY; break; default: actIdle = ACT_VM_IDLE_DEPLOYED; break; } } else { switch ( m_iClip1 ) { case 8: actIdle = ACT_VM_IDLE_8; break; case 7: actIdle = ACT_VM_IDLE_7; break; case 6: actIdle = ACT_VM_IDLE_6; break; case 5: actIdle = ACT_VM_IDLE_5; break; case 4: actIdle = ACT_VM_IDLE_4; break; case 3: actIdle = ACT_VM_IDLE_3; break; case 2: actIdle = ACT_VM_IDLE_2; break; case 1: actIdle = ACT_VM_IDLE_1; break; case 0: actIdle = ACT_VM_IDLE_EMPTY; break; default: actIdle = ACT_VM_IDLE; break; } } return actIdle; } Activity CWeaponMG42::GetPrimaryAttackActivity( void ) { Activity actPrim; if( IsDeployed() ) { switch ( m_iClip1 ) { case 8: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_8; break; case 7: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_7; break; case 6: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_6; break; case 5: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_5; break; case 4: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_4; break; case 3: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_3; break; case 2: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_2; break; case 1: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_1; break; case 0: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED_EMPTY; break; default: actPrim = ACT_VM_PRIMARYATTACK_DEPLOYED; break; } } else { switch ( m_iClip1 ) { case 8: actPrim = ACT_VM_PRIMARYATTACK_8; break; case 7: actPrim = ACT_VM_PRIMARYATTACK_7; break; case 6: actPrim = ACT_VM_PRIMARYATTACK_6; break; case 5: actPrim = ACT_VM_PRIMARYATTACK_5; break; case 4: actPrim = ACT_VM_PRIMARYATTACK_4; break; case 3: actPrim = ACT_VM_PRIMARYATTACK_3; break; case 2: actPrim = ACT_VM_PRIMARYATTACK_2; break; case 1: actPrim = ACT_VM_PRIMARYATTACK_1; break; case 0: actPrim = ACT_VM_PRIMARYATTACK_EMPTY; break; default: actPrim = ACT_VM_PRIMARYATTACK; break; } } return actPrim; } float CWeaponMG42::GetRecoil( void ) { CDODPlayer *p = ToDODPlayer( GetPlayerOwner() ); if( p && p->m_Shared.IsInMGDeploy() ) { return 0.0f; } return 20; } #ifdef CLIENT_DLL //----------------------------------------------------------------------------- // This is called after sending this entity's recording state //----------------------------------------------------------------------------- void CWeaponMG42::CleanupToolRecordingState( KeyValues *msg ) { BaseClass::CleanupToolRecordingState( msg ); // Generally, this is used to allow the entity to clean up // allocated state it put into the message, but here we're going // to use it to send particle system messages because we // know the smoke has been recorded at this point if ( !clienttools->IsInRecordingMode() || !m_pEmitter.IsValid() ) return; // NOTE: Particle system destruction message will be sent by the particle effect itself. if ( m_pEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID ) { int nId = m_pEmitter->AllocateToolParticleEffectId(); KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); msg->SetString( "name", "CWeaponMG42 smoke" ); msg->SetInt( "id", nId ); msg->SetFloat( "time", gpGlobals->curtime ); KeyValues *pEmitter0 = msg->FindKey( "DmeSpriteEmitter", true ); pEmitter0->SetInt( "count", 5 ); // particles per second, when duration is < 0 pEmitter0->SetFloat( "duration", -1 ); pEmitter0->SetString( "material", "sprites/effects/bazookapuff" ); pEmitter0->SetInt( "active", 0 ); KeyValues *pInitializers = pEmitter0->FindKey( "initializers", true ); KeyValues *pPosition = pInitializers->FindKey( "DmeRandomAttachmentPositionEntityInitializer", true ); pPosition->SetPtr( "entindex", (void*)entindex() ); pPosition->SetInt( "attachmentIndex0", 1 ); pPosition->SetInt( "attachmentIndex1", 2 ); KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true ); pLifetime->SetFloat( "minLifetime", 1.8f ); pLifetime->SetFloat( "maxLifetime", 1.8f ); KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true ); pVelocity->SetFloat( "velocityX", 0.0f ); pVelocity->SetFloat( "velocityY", 0.0f ); pVelocity->SetFloat( "velocityZ", 12.0f ); KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true ); pRoll->SetFloat( "minRoll", 0.0f ); pRoll->SetFloat( "maxRoll", 0.5f ); KeyValues *pRollSpeed = pInitializers->FindKey( "DmeSplitRandomRollSpeedInitializer", true ); pRollSpeed->SetFloat( "minRollSpeed", 0.5f ); pRollSpeed->SetFloat( "maxRollSpeed", 1.0f ); KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true ); pColor->SetColor( "color1", Color( 200, 200, 200, 255 ) ); pColor->SetColor( "color2", Color( 200, 200, 200, 255 ) ); KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true ); pAlpha->SetInt( "minStartAlpha", 60 ); pAlpha->SetInt( "maxStartAlpha", 60 ); pAlpha->SetInt( "minEndAlpha", 0 ); pAlpha->SetInt( "maxEndAlpha", 0 ); KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true ); pSize->SetFloat( "minStartSize", 4 ); pSize->SetFloat( "maxStartSize", 4 ); pSize->SetFloat( "minEndSize", 25 ); pSize->SetFloat( "maxEndSize", 25 ); KeyValues *pUpdaters = pEmitter0->FindKey( "updaters", true ); pUpdaters->FindKey( "DmePositionVelocityUpdater", true ); pUpdaters->FindKey( "DmeRollUpdater", true ); pUpdaters->FindKey( "DmeAlphaLinearUpdater", true ); pUpdaters->FindKey( "DmeSizeUpdater", true ); // create emitters for each emission rate: 5,10,20,30 KeyValues *pEmitter1 = pEmitter0->MakeCopy(); pEmitter1->SetInt( "count", 10 ); msg->AddSubKey( pEmitter1 ); KeyValues *pEmitter2 = pEmitter0->MakeCopy(); pEmitter2->SetInt( "count", 20 ); msg->AddSubKey( pEmitter2 ); KeyValues *pEmitter3 = pEmitter0->MakeCopy(); pEmitter3->SetInt( "count", 30 ); msg->AddSubKey( pEmitter3 ); // mark only the appropriate emitter active bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this; if ( !bHolstered ) { if ( m_iWeaponHeat > 85 ) { pEmitter3->SetInt( "active", 1 ); } else if ( m_iWeaponHeat > 80 ) { pEmitter2->SetInt( "active", 1 ); } else if ( m_iWeaponHeat > 65 ) { pEmitter1->SetInt( "active", 1 ); } else if ( m_iWeaponHeat > 50 ) { pEmitter0->SetInt( "active", 1 ); } } ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); } else { int nEmitterIndex = -1; bool bHolstered = GetOwner() && GetOwner()->GetActiveWeapon() != this; if ( !bHolstered ) { if ( m_iWeaponHeat > 85 ) { nEmitterIndex = 3; } else if ( m_iWeaponHeat > 80 ) { nEmitterIndex = 2; } else if ( m_iWeaponHeat > 65 ) { nEmitterIndex = 1; } else if ( m_iWeaponHeat > 50 ) { nEmitterIndex = 0; } } KeyValues *msg = new KeyValues( "ParticleSystem_ActivateEmitter" ); msg->SetInt( "id", m_pEmitter->GetToolParticleEffectId() ); msg->SetFloat( "time", gpGlobals->curtime ); msg->SetInt( "emitter", 0 ); msg->SetInt( "active", nEmitterIndex == 0 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 1 ); msg->SetInt( "active", nEmitterIndex == 1 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 2 ); msg->SetInt( "active", nEmitterIndex == 2 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->SetInt( "emitter", 3 ); msg->SetInt( "active", nEmitterIndex == 3 ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); } } #endif