예제 #1
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_FireSmoke::UpdateEffects( void )
{
	if ( m_pEmberEmitter.IsValid() )
	{
		m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() );
	}

	if ( m_pSmokeEmitter.IsValid() )
	{
		m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() );
	}

	if ( m_pFireOverlay != NULL )
	{
		m_pFireOverlay->m_vPos = GetAbsOrigin();
	}
}
예제 #2
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_RotorWashEmitter::InitSpawner( void )
{
	if ( m_pSimple.IsValid() )
		return;

	m_pSimple = WashEmitter::Create( "wash" );
	m_pSimple->SetNearClip( 128, 256 );
}
예제 #3
0
//-----------------------------------------------------------------------------
// Purpose: 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_WeaponPhysCannon::SetupEmitter( void )
{
	if ( !m_pLocalEmitter.IsValid() )
	{
		m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) );

		if ( m_pLocalEmitter.IsValid() == false )
			return false;
	}

	if ( !m_pAttractor.IsValid() )
	{
		m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" );

		if ( m_pAttractor.IsValid() == false )
			return false;
	}

	if ( !m_pEmitter.IsValid() )
	{
		m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" );

		if ( m_pEmitter.IsValid() == false )
			return false;
	}

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool C_EnvPortalPathTrack::SetupEmitters( void )
{
	// Setup the basic core emitter
	if ( m_pSimpleEmitter.IsValid() == false )
	{
		m_pSimpleEmitter = CSimpleEmitter::Create( "portaltracktrainendpoint" );

		if ( m_pSimpleEmitter.IsValid() == false )
			return false;
	}

	// Setup the attractor emitter
	if ( m_pAttractorEmitter.IsValid() == false )
	{
		m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "portaltracktrainendpointattractor" );

		if ( m_pAttractorEmitter.IsValid() == false )
			return false;
	}

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Setup the emitters we'll be using
//-----------------------------------------------------------------------------
bool C_HopwireExplosion::SetupEmitters( void )
{
	// Setup the basic core emitter
	if ( m_pSimpleEmitter.IsValid() == false )
	{
		m_pSimpleEmitter = CSimpleEmitter::Create( "hopwirecore" );

		if ( m_pSimpleEmitter.IsValid() == false )
			return false;
	}

	// Setup the attractor emitter
	if ( m_pAttractorEmitter.IsValid() == false )
	{
		m_pAttractorEmitter = CParticleAttractor::Create( GetRenderOrigin(), "hopwireattractor" );

		if ( m_pAttractorEmitter.IsValid() == false )
			return false;
	}

	return true;
}
예제 #6
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool C_AlyxEmpEffect::SetupEmitters( void )
{
	// Setup the basic core emitter
	if ( m_pSimpleEmitter.IsValid() == false )
	{
		m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" );

		if ( m_pSimpleEmitter.IsValid() == false )
			return false;
	}

	// Setup the attractor emitter
	if ( m_pAttractorEmitter.IsValid() == false )
	{
		m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" );

		if ( m_pAttractorEmitter.IsValid() == false )
			return false;
	}

	return true;
}
예제 #7
0
static void PerformNewCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &shotDir, int iMaterial, int iScale, int nFlags )
{
    bool bNoFlecks = !r_drawflecks.GetBool();
    if ( !bNoFlecks )
    {
        bNoFlecks = ( ( nFlags & FLAGS_CUSTIOM_EFFECTS_NOFLECKS ) != 0  );
    }

    // Compute the impact effect name
    const ImpactEffect_t &effect = s_pImpactEffect[ iMaterial - 'A' ];
    const char *pImpactName = effect.m_pName;
    if ( bNoFlecks && effect.m_pNameNoFlecks )
    {
        pImpactName = effect.m_pNameNoFlecks;
    }
    if ( !pImpactName )
        return;

    CSmartPtr<CNewParticleEffect> pEffect = CNewParticleEffect::Create( NULL, pImpactName );
    if ( !pEffect->IsValid() )
        return;

    Vector	vecReflect;
    float	flDot = DotProduct( shotDir, tr.plane.normal );
    VectorMA( shotDir, -2.0f * flDot, tr.plane.normal, vecReflect );

    Vector vecShotBackward;
    VectorMultiply( shotDir, -1.0f, vecShotBackward );

    Vector vecImpactPoint = ( tr.fraction != 1.0f ) ? tr.endpos : vecOrigin;
    // Other games round m_vOrigin to nearest integer, so I guess we can afford skipping this check.
#ifdef HL2_CLIENT_DLL
    Assert( VectorsAreEqual( vecOrigin, tr.endpos, 1e-1 ) );
#endif
    SetImpactControlPoint( pEffect.GetObject(), 0, vecImpactPoint, tr.plane.normal, tr.m_pEnt );
    SetImpactControlPoint( pEffect.GetObject(), 1, vecImpactPoint, vecReflect,		tr.m_pEnt );
    SetImpactControlPoint( pEffect.GetObject(), 2, vecImpactPoint, vecShotBackward,	tr.m_pEnt );
    pEffect->SetControlPoint( 3, Vector( iScale, iScale, iScale ) );
    if ( pEffect->m_pDef->ReadsControlPoint( 4 ) )
    {
        Vector vecColor;
        GetColorForSurface( &tr, &vecColor );
        pEffect->SetControlPoint( 4, vecColor );
    }
}
예제 #8
0
//-----------------------------------------------------------------------------
// Purpose: Called when data changes on the server
//-----------------------------------------------------------------------------
void C_Sparkler::OnDataChanged( DataUpdateType_t updateType )
{
	// NOTE: We MUST call the base classes' implementation of this function
	BaseClass::OnDataChanged( updateType );
	
	// Setup our entity's particle system on creation
	if ( updateType == DATA_UPDATE_CREATED )
	{
		// Creat the emitter
		m_hEmitter = CSimpleEmitter::Create( "env_sparkler" );

		// Obtain a reference handle to our particle's desired material
		if ( m_hEmitter.IsValid() )
		{
			m_hMaterial = m_hEmitter->GetPMaterial( "effects/yellowflare" );
		}

		// Spawn 128 particles per second
		m_tParticleTimer.Init( 128 );

		// Call our ClientThink() function once every client frame
		SetNextClientThink( CLIENT_THINK_ALWAYS );
	}
}
예제 #9
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_RotorWashEmitter::ClientThink( void )
{
	SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL );

	trace_t	tr;
	UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin()+(Vector(0, 0, -1024)), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER|CONTENTS_SLIME), NULL, COLLISION_GROUP_NONE, &tr );

	if ( /*!m_bIgnoreSolid && */(tr.fraction == 1.0f || tr.startsolid || tr.allsolid) )
		return;

	// If we hit the skybox, don't do it either
	if ( tr.surface.flags & SURF_SKY )
		return;

	float heightScale = RemapValClamped( tr.fraction * 1024, 512, 1024, 1.0f, 0.0f );

	Vector vecDustColor;

	if ( tr.contents & CONTENTS_WATER )
	{
		vecDustColor.x = 0.8f;
		vecDustColor.y = 0.8f;
		vecDustColor.z = 0.75f;
	}
	else if ( tr.contents & CONTENTS_SLIME )
	{
		vecDustColor.x = 0.6f;
		vecDustColor.y = 0.5f;
		vecDustColor.z = 0.15f;
	}
	else
	{
		vecDustColor.x = 0.35f;
		vecDustColor.y = 0.3f;
		vecDustColor.z = 0.25f;
	}

#ifndef _XBOX

	InitSpawner();

	if ( m_pSimple.IsValid() == false )
		return;

	m_pSimple->SetSortOrigin( GetAbsOrigin() );

	PMaterialHandle	*hMaterial;
	
	// Cache and set our material based on the surface we're over (ie. water)
	if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
	{
		if ( m_hWaterMaterial[0] == NULL )
		{
			m_hWaterMaterial[0] = m_pSimple->GetPMaterial("effects/splash1");
			m_hWaterMaterial[1] = m_pSimple->GetPMaterial("effects/splash2");
		}
		hMaterial = m_hWaterMaterial;
	}
	else
	{
		hMaterial = g_Mat_DustPuff;
	}

#endif // !XBOX

	// If we're above water, make ripples
	if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
	{
		float flScale = random->RandomFloat( 7.5f, 8.5f );

		Vector	color = Vector( 0.8f, 0.8f, 0.75f );
		Vector startPos = tr.endpos + Vector(0,0,8);
		Vector endPos = tr.endpos + Vector(0,0,-64);

		if ( tr.fraction < 1.0f )
		{
			//Add a ripple quad to the surface
			FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ), 
						tr.plane.normal, 
						64.0f * flScale, 
						128.0f * flScale, 
						0.8f,
						0.75f * heightScale, 
						0.0f,
						0.75f,
						random->RandomFloat( 0, 360 ),
						random->RandomFloat( -2.0f, 2.0f ),
						vecDustColor, 
						0.2f,  
						"effects/splashwake3",
						(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
		}
	}

#ifndef _XBOX
	int		numRingSprites = 32;
	float	yaw = random->RandomFloat( 0, 2*M_PI ); // Randomly placed on the unit circle
	float	yawIncr = (2*M_PI) / numRingSprites;
	Vector	vecForward;
	Vector	offset;
	SimpleParticle	*pParticle;

	// Draw the rings
	for ( int i = 0; i < numRingSprites; i++ )
	{
		// Get our x,y on the unit circle
		SinCos( yaw, &vecForward.y, &vecForward.x );
		
		// Increment ahead
		yaw += yawIncr;

		// @NOTE toml (3-28-07): broke out following expression because vc2005 optimizer was screwing up in presence of SinCos inline assembly. Would also
		// go away if offset were referenced below as in the AddLineOverlay()
		//offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( vecForward * 128.0f );

		offset = vecForward * 128.0f;
		offset += tr.endpos + RandomVector( -4.0f, 4.0f );


		pParticle = (SimpleParticle *) m_pSimple->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset );

		if ( pParticle != NULL )
		{
			pParticle->m_flLifetime = 0.0f;
			pParticle->m_flDieTime	= random->RandomFloat( 0.25f, 1.0f );

			pParticle->m_vecVelocity = vecForward * random->RandomFloat( 1000, 1500 );
		
			#if __EXPLOSION_DEBUG
			debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
			#endif

			if ( tr.contents & CONTENTS_SLIME )
			{
				vecDustColor.x = random->RandomFloat( 0.4f, 0.6f );
				vecDustColor.y = random->RandomFloat( 0.3f, 0.5f );
				vecDustColor.z = random->RandomFloat( 0.1f, 0.2f );
			}

			pParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
			pParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
			pParticle->m_uchColor[2] = vecDustColor.z * 255.0f;

			pParticle->m_uchStartSize	= random->RandomInt( 16, 64 );
			pParticle->m_uchEndSize		= pParticle->m_uchStartSize * 4;

			pParticle->m_uchStartAlpha	= random->RandomFloat( 16, 32 ) * heightScale;
			pParticle->m_uchEndAlpha	= 0;
			
			pParticle->m_flRoll			= random->RandomInt( 0, 360 );
			pParticle->m_flRollDelta	= random->RandomFloat( -16.0f, 16.0f );
		}
	}
#endif // !XBOX
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : fTimeDelta - 
//-----------------------------------------------------------------------------
void C_ExtinguisherJet::Update( float fTimeDelta )
{
	if ( m_bEmit == false )
		return;

	C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();

	if ( m_bUseMuzzlePoint )
	{
		C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL;

		if ( vm )
		{
			int iAttachment = vm->LookupAttachment( "muzzle" );
			Vector origin;
			QAngle angles;
			vm->GetAttachment( iAttachment, origin, angles );

			Assert( !GetMoveParent() );
			SetLocalOrigin( origin );
			SetLocalAngles( angles );
		}
	}

	trace_t	tr;
	Vector	shotDir, vRight, vUp;

	AngleVectors( GetAbsAngles(), &shotDir, &vRight, &vUp );
	
	//FIXME: Muzzle point is incorrect on the model!
	if ( m_bUseMuzzlePoint )
	{
		shotDir.Negate();
	}

	Vector	endPoint = GetAbsOrigin() + ( shotDir * 150.0f );
	
	UTIL_TraceLine( GetAbsOrigin(), endPoint, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &tr );

	bool	hitWall = ( tr.fraction < 1.0f );

	//Add normal jet
	if ( m_pEmitter.IsValid() )
	{
		SimpleParticle	*pParticle;

		m_pEmitter->SetSortOrigin( GetAbsOrigin() );
	
		float tempDelta = fTimeDelta;
		
		//FIXME: All particles need to be within this loop
		while( m_ParticleSpawn.NextEvent( tempDelta ) )
		{
			pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() );

			if ( pParticle )
			{
				pParticle->m_flDieTime	= 0.2f;
				pParticle->m_flLifetime	= 0.0f;
				
				pParticle->m_flRoll		= random->RandomInt( 0, 360 );
				pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f );
				
				pParticle->m_uchStartSize	= 1;
				pParticle->m_uchEndSize		= random->RandomInt( 32, 48 );
				pParticle->m_uchStartAlpha	= random->RandomInt( 128, 164 );
				pParticle->m_uchEndAlpha	= 0;
				
				int	cScale = random->RandomInt( 192, 255 );
				pParticle->m_uchColor[0]	= cScale;
				pParticle->m_uchColor[1]	= cScale;
				pParticle->m_uchColor[2]	= cScale;

				Vector	dir;
				QAngle  ofsAngles;

				ofsAngles.Random( -8.0f, 8.0f );
				ofsAngles += GetAbsAngles();

				AngleVectors( ofsAngles, &dir );

				if ( m_bUseMuzzlePoint )
				{
					dir.Negate();
				}

				pParticle->m_vecVelocity	= dir * random->RandomInt( 400, 800 );
			}

			//Add muzzle effect
			pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() );

			if ( pParticle )
			{
				pParticle->m_flDieTime	= 0.1f;
				pParticle->m_flLifetime	= 0.0f;
				
				pParticle->m_flRoll		= random->RandomInt( 0, 360 );
				pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f );
				
				pParticle->m_uchStartSize	= 1;
				pParticle->m_uchEndSize		= random->RandomInt( 8, 16 );
				pParticle->m_uchStartAlpha	= random->RandomInt( 128, 255 );
				pParticle->m_uchEndAlpha	= 0;
				
				int	cScale = random->RandomInt( 192, 255 );
				pParticle->m_uchColor[0]	= cScale;
				pParticle->m_uchColor[1]	= cScale;
				pParticle->m_uchColor[2]	= cScale;

				Vector	dir;
				QAngle  ofsAngles;

				ofsAngles.Random( -64.0f, 64.0f );
				ofsAngles += GetAbsAngles();

				AngleVectors( ofsAngles, &dir );

				if ( m_bUseMuzzlePoint )
				{
					dir.Negate();
				}

				pParticle->m_vecVelocity	= dir * random->RandomInt( 32, 64 );
			}

			//Add a wall effect if needed
			if ( hitWall )
			{
				AddExtinguisherDecal( tr );

				Vector	offDir;

				offDir.Random( -16.0f, 16.0f );

				pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, ( tr.endpos + ( tr.plane.normal * 8.0f ) ) + offDir );

				if ( pParticle )
				{
					pParticle->m_flDieTime	= 0.4f;
					pParticle->m_flLifetime	= 0.0f;
					
					pParticle->m_flRoll		= random->RandomInt( 0, 360 );
					pParticle->m_flRollDelta= random->RandomFloat( -2.0f, 2.0f );
					
					pParticle->m_uchStartSize	= random->RandomInt( 8, 16 );
					pParticle->m_uchEndSize		= random->RandomInt( 24, 32 );
					pParticle->m_uchStartAlpha	= random->RandomInt( 64, 128 );
					pParticle->m_uchEndAlpha	= 0;
					
					int	cScale = random->RandomInt( 192, 255 );
					pParticle->m_uchColor[0]	= cScale;
					pParticle->m_uchColor[1]	= cScale;
					pParticle->m_uchColor[2]	= cScale;

					Vector	rDir;

					rDir = tr.plane.normal;
					rDir[0] += random->RandomFloat( -0.9f, 0.9f );
					rDir[1] += random->RandomFloat( -0.9f, 0.9f );
					rDir[2] += random->RandomFloat( -0.9f, 0.9f );

					pParticle->m_vecVelocity = rDir * random->RandomInt( 32, 64 );
				}			
			}

			//Add small ember-like particles
			if ( random->RandomInt( 0, 1 ) == 0 )
			{
				m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() );

				pParticle = (SimpleParticle *) m_pEmberEmitter->AddParticle( sizeof(SimpleParticle), m_pEmberEmitter->GetPMaterial( "particle/particle_smokegrenade" ), GetAbsOrigin() );
				
				assert(pParticle);

				if ( pParticle )
				{
					pParticle->m_flLifetime		= 0.0f;
					pParticle->m_flDieTime		= 1.0f;

					pParticle->m_flRoll			= 0;
					pParticle->m_flRollDelta	= 0;

					pParticle->m_uchColor[0]	= 255;
					pParticle->m_uchColor[1]	= 255;
					pParticle->m_uchColor[2]	= 255;
					pParticle->m_uchStartAlpha	= 255;
					pParticle->m_uchEndAlpha	= 0;
					pParticle->m_uchStartSize	= 1;
					pParticle->m_uchEndSize		= 0;
					
					Vector	dir;
					QAngle  ofsAngles;

					ofsAngles.Random( -8.0f, 8.0f );
					ofsAngles += GetAbsAngles();

					AngleVectors( ofsAngles, &dir );

					if ( m_bUseMuzzlePoint )
					{
						dir.Negate();
					}

					pParticle->m_vecVelocity	= dir * random->RandomInt( 400, 800 );
				}
			}
		}
	}

	// Inner beam

	CBeamSegDraw	beamDraw;
	CBeamSeg		seg;
	const int		numPoints = 4;
	Vector			beamPoints[numPoints];

	beamPoints[0] = GetAbsOrigin();

	// Create our beam points
	int i;
	for ( i = 0; i < numPoints; i++ )
	{
		beamPoints[i] = GetAbsOrigin() + ( shotDir * (32*i*i) );

		beamPoints[i] += vRight * sin( gpGlobals->curtime * 4.0f ) * (2.0f*i);
		beamPoints[i] += vUp * sin( gpGlobals->curtime * 8.0f ) * (1.0f*i);
		beamPoints[i] += shotDir * sin( gpGlobals->curtime * (16.0f*i) ) * (1.0f*i);
	}

	IMaterial *pMat = materials->FindMaterial( "particle/particle_smokegrenade", NULL );

	beamDraw.Start( numPoints, pMat );

	//Setup and draw those points	
	for( i = 0; i < numPoints; i++ )
	{
		float	t = (float) i / (numPoints - 1);
		float	color = 1.0f * (1.0f - t);

		seg.m_vColor		= Vector( color, color, color );
		seg.m_vPos			= beamPoints[i];
		seg.m_flTexCoord	= (float)i/(float)(numPoints-1) - ((gpGlobals->curtime - (int)gpGlobals->curtime) * 4.0f );
		seg.m_flWidth		= 4.0f + ( (64.0f*t) * (fabs( sin( gpGlobals->curtime * 16.0f ) )) );
		seg.m_flAlpha		= color;

		beamDraw.NextSeg( &seg );
	}
	
	beamDraw.End();
}
예제 #11
0
파일: fx_sparks.cpp 프로젝트: Yosam02/game
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : origin - 
//			normal - 
//-----------------------------------------------------------------------------
void FX_ConcussiveExplosion(Vector &origin, Vector &normal)
{
    VPROF_BUDGET("FX_ConcussiveExplosion", VPROF_BUDGETGROUP_PARTICLE_RENDERING);
    Vector	offset = origin + (normal * 2.0f);
    Vector	dir;
    int		i;

    // 
    // Smoke
    //

    CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create("FX_ConcussiveExplosion 1");
    pSmokeEmitter->SetSortOrigin(offset);

    //Quick moving sprites
    for (i = 0; i < 16; i++)
    {
        SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle(sizeof(SimpleParticle), g_Mat_DustPuff[1], offset);

        if (pParticle == NULL)
            return;

        pParticle->m_flLifetime = 0.0f;
        pParticle->m_flDieTime = random->RandomFloat(0.2f, 0.4f);
        pParticle->m_uchStartSize = random->RandomInt(4, 8);
        pParticle->m_uchEndSize = random->RandomInt(32, 64);

        dir[0] = random->RandomFloat(-1.0f, 1.0f);
        dir[1] = random->RandomFloat(-1.0f, 1.0f);
        dir[2] = random->RandomFloat(-1.0f, 1.0f);

        pParticle->m_vecVelocity = dir * random->RandomFloat(64.0f, 128.0f);
        pParticle->m_uchStartAlpha = random->RandomInt(64, 128);
        pParticle->m_uchEndAlpha = 0;
        pParticle->m_flRoll = random->RandomFloat(180, 360);
        pParticle->m_flRollDelta = random->RandomFloat(-4, 4);

        int colorRamp = random->RandomFloat(235, 255);
        pParticle->m_uchColor[0] = colorRamp;
        pParticle->m_uchColor[1] = colorRamp;
        pParticle->m_uchColor[2] = colorRamp;
    }

    //Slow lingering sprites
    for (i = 0; i < 2; i++)
    {
        SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle(sizeof(SimpleParticle), g_Mat_DustPuff[1], offset);
        if (pParticle == NULL)
            return;

        pParticle->m_flLifetime = 0.0f;
        pParticle->m_flDieTime = random->RandomFloat(1.0f, 2.0f);
        pParticle->m_uchStartSize = random->RandomInt(32, 64);
        pParticle->m_uchEndSize = random->RandomInt(100, 128);

        dir[0] = normal[0] + random->RandomFloat(-0.8f, 0.8f);
        dir[1] = normal[1] + random->RandomFloat(-0.8f, 0.8f);
        dir[2] = normal[2] + random->RandomFloat(-0.8f, 0.8f);

        pParticle->m_vecVelocity = dir * random->RandomFloat(16.0f, 32.0f);

        pParticle->m_uchStartAlpha = random->RandomInt(32, 64);
        pParticle->m_uchEndAlpha = 0;
        pParticle->m_flRoll = random->RandomFloat(180, 360);
        pParticle->m_flRollDelta = random->RandomFloat(-1, 1);

        int colorRamp = random->RandomFloat(235, 255);
        pParticle->m_uchColor[0] = colorRamp;
        pParticle->m_uchColor[1] = colorRamp;
        pParticle->m_uchColor[2] = colorRamp;
    }


    //	
    // Quick sphere
    //

    CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create("FX_ConcussiveExplosion 2");

    pSimple->SetSortOrigin(offset);

    SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle(sizeof(SimpleParticle), pSimple->GetPMaterial("effects/blueflare1"), offset);

    if (pParticle)
    {
        pParticle->m_flLifetime = 0.0f;
        pParticle->m_flDieTime = 0.1f;
        pParticle->m_vecVelocity.Init();
        pParticle->m_flRoll = random->RandomFloat(180, 360);
        pParticle->m_flRollDelta = random->RandomFloat(-1, 1);

        pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 128;

        pParticle->m_uchStartAlpha = 255;
        pParticle->m_uchEndAlpha = 0;

        pParticle->m_uchStartSize = 16;
        pParticle->m_uchEndSize = 64;
    }

    pParticle = (SimpleParticle *) pSimple->AddParticle(sizeof(SimpleParticle), pSimple->GetPMaterial("effects/blueflare1"), offset);

    if (pParticle)
    {
        pParticle->m_flLifetime = 0.0f;
        pParticle->m_flDieTime = 0.2f;
        pParticle->m_vecVelocity.Init();
        pParticle->m_flRoll = random->RandomFloat(180, 360);
        pParticle->m_flRollDelta = random->RandomFloat(-1, 1);
        pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 32;

        pParticle->m_uchStartAlpha = 64;
        pParticle->m_uchEndAlpha = 0;

        pParticle->m_uchStartSize = 64;
        pParticle->m_uchEndSize = 128;
    }


    //
    // Dlight
    //

    dlight_t *dl = effects->CL_AllocDlight(0);

    dl->origin = offset;
    dl->color.r = dl->color.g = dl->color.b = 64;
    dl->radius = random->RandomFloat(128, 256);
    dl->die = gpGlobals->curtime + 0.1;


    //
    // Moving lines
    //

    TrailParticle	*pTrailParticle;
    CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create("FX_ConcussiveExplosion 3");
    PMaterialHandle hMaterial;
    int				numSparks;

    if (pSparkEmitter.IsValid())
    {
        hMaterial = pSparkEmitter->GetPMaterial("effects/blueflare1");

        pSparkEmitter->SetSortOrigin(offset);
        pSparkEmitter->m_ParticleCollision.SetGravity(0.0f);

        numSparks = random->RandomInt(16, 32);

        //Dump out sparks
        for (i = 0; i < numSparks; i++)
        {
            pTrailParticle = (TrailParticle *) pSparkEmitter->AddParticle(sizeof(TrailParticle), hMaterial, offset);

            if (pTrailParticle == NULL)
                return;

            pTrailParticle->m_flLifetime = 0.0f;

            dir.Random(-1.0f, 1.0f);

            pTrailParticle->m_flWidth = random->RandomFloat(1.0f, 2.0f);
            pTrailParticle->m_flLength = random->RandomFloat(0.01f, 0.1f);
            pTrailParticle->m_flDieTime = random->RandomFloat(0.1f, 0.2f);

            pTrailParticle->m_vecVelocity = dir * random->RandomFloat(800, 1000);

            float colorRamp = random->RandomFloat(0.75f, 1.0f);
            FloatToColor32(pTrailParticle->m_color, colorRamp, colorRamp, 1.0f, 1.0f);
        }
    }

    //Moving particles
    CSmartPtr<CTrailParticles> pCollisionEmitter = CTrailParticles::Create("FX_ConcussiveExplosion 4");

    if (pCollisionEmitter.IsValid())
    {
        //Setup our collision information
        pCollisionEmitter->Setup((Vector &) offset,
            NULL,
            SPARK_ELECTRIC_SPREAD,
            SPARK_ELECTRIC_MINSPEED * 6,
            SPARK_ELECTRIC_MAXSPEED * 6,
            -400,
            SPARK_ELECTRIC_DAMPEN,
            bitsPARTICLE_TRAIL_FADE);

        pCollisionEmitter->SetSortOrigin(offset);

        numSparks = random->RandomInt(8, 16);
        hMaterial = pCollisionEmitter->GetPMaterial("effects/blueflare1");

        //Dump out sparks
        for (i = 0; i < numSparks; i++)
        {
            pTrailParticle = (TrailParticle *) pCollisionEmitter->AddParticle(sizeof(TrailParticle), hMaterial, offset);

            if (pTrailParticle == NULL)
                return;

            pTrailParticle->m_flLifetime = 0.0f;

            dir.Random(-1.0f, 1.0f);
            dir[2] = random->RandomFloat(0.0f, 0.75f);

            pTrailParticle->m_flWidth = random->RandomFloat(1.0f, 2.0f);
            pTrailParticle->m_flLength = random->RandomFloat(0.01f, 0.1f);
            pTrailParticle->m_flDieTime = random->RandomFloat(0.2f, 1.0f);

            pTrailParticle->m_vecVelocity = dir * random->RandomFloat(128, 512);

            float colorRamp = random->RandomFloat(0.75f, 1.0f);
            FloatToColor32(pTrailParticle->m_color, colorRamp, colorRamp, 1.0f, 1.0f);
        }
    }
}