void FX_GrenadeAltThink( centity_t *cent, const struct weaponInfo_s *weapon )
{
	vec3_t	dir, org;

	VectorCopy( cent->gent->s.pos.trDelta, dir );
	VectorNormalize( dir );

	// Move away from the ent origin so that the glow doesn't clip into the model so much.
	VectorMA( cent->lerpOrigin, 1.4, dir, org );

	FX_AddQuad( org, dir, NULL, NULL, 12.0f + random() * 32.0f, 0.0f, 0.75f, 0.75f, 0, 0, 0.0f, 1, cgs.media.dkorangeParticleShader );
	if ( rand() & 1 )
		FX_AddQuad( org, dir, NULL, NULL, 28.0f + random() * 32.0f, 0.0f, 0.5f, 0.5f, 0, 0, 0.0f, 1, cgs.media.yellowParticleShader );

	if ( cent->gent )
	{
		vec3_t rgb = { 1.0f, 1.0f, 0.4f }, rgb2 = { 1.0f, 0.5f, 0.0f };

		// This flag controls whether or not the thing was initial fire, or shrapnel
		if ( cent->gent->trigger_formation )
			// Shot from first person so beef it up a bit...
			FX_AddLine( cent->lerpOrigin,  cent->gent->pos2, 1.0f, 4.0f, 8.0f, 0.7f, 0.1f, rgb, rgb2, 200, cgs.media.whiteLaserShader );
		else
			FX_AddLine( cent->lerpOrigin,  cent->gent->pos2, 1.0f, 16.0f, 4.0f, 0.2f, 0.1f, rgb, rgb2, 100, cgs.media.whiteLaserShader );

		VectorCopy( cent->lerpOrigin, cent->gent->pos2 );
	}
}
Пример #2
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &origin - 
//			&normal - 
//			scale - 
//-----------------------------------------------------------------------------
void FX_WaterRipple( const Vector &origin, float scale, Vector *pColor, float flLifetime, float flAlpha )
{
	VPROF_BUDGET( "FX_WaterRipple", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
	trace_t	tr;

	Vector	color = pColor ? *pColor : Vector( 0.8f, 0.8f, 0.75f );

	Vector startPos = origin + Vector(0,0,8);
	Vector endPos = origin + Vector(0,0,-64);

	UTIL_TraceLine( startPos, endPos, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
	
	if ( tr.fraction < 1.0f )
	{
		//Add a ripple quad to the surface
		FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ), 
					tr.plane.normal, 
					16.0f*scale, 
					128.0f*scale, 
					0.7f,
					flAlpha,	// start alpha
					0.0f,		// end alpha
					0.25f,
					random->RandomFloat( 0, 360 ),
					random->RandomFloat( -16.0f, 16.0f ),
					color, 
					flLifetime, 
					"effects/splashwake1", 
					(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Parameter heavy version
//-----------------------------------------------------------------------------
void FX_AddQuad( const Vector &origin, 
				 const Vector &normal, 
				 float startSize, 
				 float endSize, 
				 float sizeBias,
				 float startAlpha, 
				 float endAlpha,
				 float alphaBias,
				 float yaw,
				 float deltaYaw,
				 const Vector &color, 
				 float lifeTime, 
				 const char *shader, 
				 unsigned int flags )
{
	FXQuadData_t data;

	//Setup the data
	data.SetAlpha( startAlpha, endAlpha );
	data.SetScale( startSize, endSize );
	data.SetFlags( flags );
	data.SetMaterial( shader );
	data.SetNormal( normal );
	data.SetOrigin( origin );
	data.SetLifeTime( lifeTime );
	data.SetColor( color[0], color[1], color[2] );
	data.SetScaleBias( sizeBias );
	data.SetAlphaBias( alphaBias );
	data.SetYaw( yaw, deltaYaw );

	//Output it
	FX_AddQuad( data );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int C_MortarShell::DrawModel( int flags )
{
	if ( gpGlobals->frametime <= 0.0f )
		return 0;

	float flPerc;
	bool ending;

	// See if we're in the beginning phase
	if ( gpGlobals->curtime < ( m_flStarttime + m_flLifespan ) )
	{
		flPerc = GetStartPerc();
		ending = false;
	}
	else
	{
		flPerc = GetEndPerc();
		ending = true;
	}

	float flAlpha = ALPHA_MIN + ( ( ALPHA_MAX - ALPHA_MIN ) * flPerc );
	float flScale = ( ending ) ? m_flRadius : ( (m_flRadius*0.1f)+ ( ( m_flRadius - (m_flRadius*0.1f) ) * flPerc ) );

	// Do the ground effect
	FX_AddQuad( GetAbsOrigin() + ( m_vecSurfaceNormal * 2.0f ), 
				m_vecSurfaceNormal, 
				flScale,
				flScale,
				1.0f, 
				flAlpha,
				flAlpha,
				1.0f,
				0,
				0,
				Vector( 1.0f, 1.0f, 1.0f ),
				0.0001f, 
				"effects/combinemuzzle2_nocull",
				0 );

	if ( !ending )
	{
		// Add extra effects on startup
		AddRisingParticles( flPerc );
	}
	else
	{
		// Add exploding particles after the impact
		AddExplodingParticles( flPerc );
	}

	return 1;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &data - 
//-----------------------------------------------------------------------------
void CombineBallImpactCallback( const CEffectData &data )
{
	// Quick flash
	FX_AddQuad( data.m_vOrigin,
				data.m_vNormal,
				data.m_flRadius * 10.0f,
				0,
				0.75f, 
				1.0f,
				0.0f,
				0.4f,
				random->RandomInt( 0, 360 ), 
				0,
				Vector( 1.0f, 1.0f, 1.0f ), 
				0.25f, 
				"effects/combinemuzzle1_nocull",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );

	// Lingering burn
	FX_AddQuad( data.m_vOrigin,
				data.m_vNormal, 
				data.m_flRadius * 2.0f,
				data.m_flRadius * 4.0f,
				0.75f, 
				1.0f,
				0.0f,
				0.4f,
				random->RandomInt( 0, 360 ), 
				0,
				Vector( 1.0f, 1.0f, 1.0f ), 
				0.5f, 
				"effects/combinemuzzle2_nocull",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );

	// Throw sparks
	FX_ElectricSpark( data.m_vOrigin, 2, 1, &data.m_vNormal );
}
Пример #6
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &data - 
//-----------------------------------------------------------------------------
void AR2ImpactCallback( const CEffectData &data )
{
	FX_AddQuad( data.m_vOrigin, 
				data.m_vNormal, 
				random->RandomFloat( 24, 32 ),
				0,
				0.75f, 
				1.0f,
				0.0f,
				0.4f,
				random->RandomInt( 0, 360 ), 
				0,
				Vector( 1.0f, 1.0f, 1.0f ), 
				0.25f, 
				"effects/combinemuzzle2_nocull",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
}
void FX_BlowBits( vec3_t start, vec3_t end, vec3_t dir, vec3_t user )
{
	vec3_t	diff, org;
	float	len;
	FXLine	*fx;

	VectorSubtract( end, start, diff );
	len = VectorNormalize( diff ) * ( 0.2 + random() * 0.3 );
	VectorMA( start, len, diff, org );

	fx = FX_AddLine( end, start, (int)(random() * 3.2f), 2.0f + random() * 2, 0, 0.5f, 0.1f, 150 + random() * 150, cgs.media.orangeTrailShader ); 

	if ( fx == NULL )
		return;
	
	fx->SetFlags( FXF_SHRINK );

	FX_AddQuad( end, dir, NULL, NULL, 1.0f, 64.0f, 1.0, 0.0, random() * 360.0f, 0.0f, 0.0, 200, cgs.media.orangeRingShader );
	// FX_AddQuad( end, dir, NULL, NULL, 20.0, -15.0, 0.6, 0.4, 0.0,0.0,0.0,450, cgs.media.borgEyeFlareShader );
}
void FX_GrenadeExplode( vec3_t origin, vec3_t normal )
{
	localEntity_t	*le;
	FXTrail			*fx;
	vec3_t			direction, org;

	VectorSet( direction, 0,0,1 );

	// Add an explosion and tag a light to it
	le = CG_MakeExplosion( origin, direction, cgs.media.nukeModel, 5, NULL, 250, qfalse, 25.0f, LEF_FADE_RGB );
	le->light = 150;
	le->refEntity.renderfx |= RF_NOSHADOW;

	VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f );

	// Ground ring
	FX_AddQuad( origin, normal, NULL, NULL, 5, 330, 1.0, 0.0, random() * 360, 0, 0, 300, cgs.media.bigShockShader );
	// Flare
	VectorMA( origin, 12, direction, org );
	FX_AddSprite( org, NULL, NULL, 160.0, -540.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );

	for ( int i = 0; i < 12; i++)
	{
		fx = FX_AddTrail( origin, NULL, NULL, 24.0f + random() * 12, -40.0f,
								0.5 + random() * 2, -3.0, 1.0f, 1.0f, 0.5f, 1000.0f,  cgs.media.orangeTrailShader, rand() & FXF_BOUNCE );


		if ( fx == NULL )
			return;
		
		FXE_Spray( normal, 470, 325, 0.5f, 700, (FXPrimitive *) fx );
	}

	cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSnd );	

	// Smoke and impact
	CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, 
					random() * 16 + 48, qfalse );

	CG_ExplosionEffects( origin, 3.0f, 400 );
}
Пример #9
0
//-----------------------------------------------------------------------------
// Purpose: Draw a cheap glow quad at our impact point (with sparks)
//-----------------------------------------------------------------------------
void StunstickImpactCallback( const CEffectData &data )
{
	float scale = random->RandomFloat( 16, 32 );

	FX_AddQuad( data.m_vOrigin, 
				data.m_vNormal, 
				scale,
				scale*2.0f,
				1.0f, 
				1.0f,
				0.0f,
				0.0f,
				random->RandomInt( 0, 360 ), 
				0,
				Vector( 1.0f, 1.0f, 1.0f ), 
				0.1f, 
				"sprites/light_glow02_add",
				0 );

	FX_Sparks( data.m_vOrigin, 1, 2, data.m_vNormal, 6, 64, 256 );
}
Пример #10
0
void FX_GrenadeExplode( vec3_t origin, vec3_t normal )
{
	localEntity_t	*le;
	qhandle_t	null = 0;
	vec3_t			direction, org, vel;
	int i;

	VectorSet( direction, 0,0,1 );

	// Add an explosion and tag a light to it
	le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, null, 250, qfalse, 25.0f, LEF_FADE_RGB);
	le->light = 150;
	le->refEntity.renderfx |= RF_NOSHADOW;

	VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f );

	// Ground ring
	FX_AddQuad( origin, normal, 5, 100, 1.0, 0.0, random() * 360, 300, cgs.media.bigShockShader );
	// Flare
	VectorMA( origin, 12, direction, org );
	FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE );

	for (i = 0; i < 12; i++)
	{
		float width, length;
		FXE_Spray( normal, 470, 325, 0.5f, vel);
		length = 24.0 + random() * 12;
		width = 0.5 + random() * 2;
		FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, 
						1.0f, 1.0f, 0.5f, 1000.0f,  cgs.media.orangeTrailShader);
	}

	trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound );	

	// Smoke and impact
//	FX_AddSpawner( origin, normal, NULL, NULL, 100, 25.0f, 2000.0f, (void *) CG_SmokeSpawn, NULL, 1024 );
	CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, 
				random() * 16 + 48, qfalse );
}
Пример #11
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &origin - 
//			&normal - 
//			scale - 
//-----------------------------------------------------------------------------
void FX_AirboatGunImpact( const Vector &origin, const Vector &normal, float scale )
{
#ifdef _XBOX

	Vector offset = origin + ( normal * 1.0f );

	CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "FX_MetalSpark 1" );

	if ( sparkEmitter == NULL )
		return;

	//Setup our information
	sparkEmitter->SetSortOrigin( offset );
	sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
	sparkEmitter->SetVelocityDampen( 8.0f );
	sparkEmitter->SetGravity( 800.0f );
	sparkEmitter->SetCollisionDamped( 0.25f );
	sparkEmitter->GetBinding().SetBBox( offset - Vector( 32, 32, 32 ), offset + Vector( 32, 32, 32 ) );

	int	numSparks = random->RandomInt( 4, 8 );

	TrailParticle	*pParticle;
	PMaterialHandle	hMaterial = sparkEmitter->GetPMaterial( "effects/spark" );
	Vector			dir;

	float	length	= 0.1f;

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

		if ( pParticle == NULL )
			return;

		pParticle->m_flLifetime	= 0.0f;
		pParticle->m_flDieTime	= random->RandomFloat( 0.05f, 0.1f );

		float	spreadOfs = random->RandomFloat( 0.0f, 2.0f );

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

		VectorNormalize( dir );

		pParticle->m_flWidth		= random->RandomFloat( 1.0f, 4.0f );
		pParticle->m_flLength		= random->RandomFloat( length*0.25f, length );

		pParticle->m_vecVelocity	= dir * random->RandomFloat( (128.0f*(2.0f-spreadOfs)), (512.0f*(2.0f-spreadOfs)) );

		Color32Init( pParticle->m_color, 255, 255, 255, 255 );
	}

#else

	// Normal metal spark
	FX_MetalSpark( origin, normal, normal, (int) scale );

#endif // _XBOX

	// Add a quad to highlite the hit point
	FX_AddQuad( origin, 
				normal, 
				random->RandomFloat( 16, 32 ),
				random->RandomFloat( 32, 48 ),
				0.75f, 
				1.0f,
				0.0f,
				0.4f,
				random->RandomInt( 0, 360 ), 
				0,
				Vector( 1.0f, 1.0f, 1.0f ), 
				0.05f, 
				"effects/combinemuzzle2_nocull",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
}
Пример #12
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_WaterExplosionEffect::CreateCore( void )
{
	if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
		return;

	// Get our lighting information for the water surface
	Vector	color;
	float	luminosity;
	FX_GetSplashLighting( m_vecWaterSurface + Vector( 0, 0, 8 ), &color, &luminosity );

	float lifetime = random->RandomFloat( 0.8f, 1.0f );

	// Ground splash
	FX_AddQuad( m_vecWaterSurface + Vector(0,0,2), 
				Vector(0,0,1), 
				64, 
				64 * 4.0f,
				0.85f, 
				luminosity,
				0.0f,
				0.25f,
				random->RandomInt( 0, 360 ), 
				random->RandomFloat( -4, 4 ), 
				color,
				2.0f,
				"effects/splashwake1",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );

	Vector	vRight, vUp;
	VectorVectors( Vector(0,0,1) , vRight, vUp );

	Vector	start, end;
	
	float radius = 50.0f;

	unsigned int flags;

	// Base vertical shaft
	FXLineData_t lineData;

	start = m_vecWaterSurface;
	end = start + ( Vector( 0, 0, 1 ) * random->RandomFloat( radius, radius*1.5f ) );

	if ( random->RandomInt( 0, 1 ) )
	{
		flags |= FXSTATICLINE_FLIP_HORIZONTAL;
	}
	else
	{
		flags = 0;
	}

	lineData.m_flDieTime = lifetime * 0.5f;
	
	lineData.m_flStartAlpha= luminosity;
	lineData.m_flEndAlpha = 0.0f;
	
	lineData.m_flStartScale = radius*0.5f;
	lineData.m_flEndScale = radius*2; 

	lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );

	lineData.m_vecStart = start;
	lineData.m_vecStartVelocity = vec3_origin;

	lineData.m_vecEnd = end;
	lineData.m_vecEndVelocity = Vector(0,0,random->RandomFloat( 650, 750 ));

	FX_AddLine( lineData );

	// Inner filler shaft
	start = m_vecWaterSurface;
	end = start + ( Vector(0,0,1) * random->RandomFloat( 32, 64 ) );

	if ( random->RandomInt( 0, 1 ) )
	{
		flags |= FXSTATICLINE_FLIP_HORIZONTAL;
	}
	else
	{
		flags = 0;
	}

	lineData.m_flDieTime = lifetime * 0.5f;
	
	lineData.m_flStartAlpha= luminosity;
	lineData.m_flEndAlpha = 0.0f;
	
	lineData.m_flStartScale = radius;
	lineData.m_flEndScale = radius*2; 

	lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );

	lineData.m_vecStart = start;
	lineData.m_vecStartVelocity = vec3_origin;

	lineData.m_vecEnd = end;
	lineData.m_vecEndVelocity = Vector(0,0,1) * random->RandomFloat( 64, 128 );

	FX_AddLine( lineData );
}
Пример #13
0
void FX_MetalSpark(const Vector &position, const Vector &direction, const Vector &surfaceNormal, int iScale)
{
    VPROF_BUDGET("FX_MetalSpark", VPROF_BUDGETGROUP_PARTICLE_RENDERING);

    if (!fx_drawmetalspark.GetBool())
        return;

    //
    // Emitted particles
    //

    Vector offset = position + (surfaceNormal * 1.0f);

    CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create("FX_MetalSpark 1");

    if (sparkEmitter == NULL)
        return;

    //Setup our information
    sparkEmitter->SetSortOrigin(offset);
    sparkEmitter->SetFlag(bitsPARTICLE_TRAIL_VELOCITY_DAMPEN);
    sparkEmitter->SetVelocityDampen(8.0f);
    sparkEmitter->SetGravity(METAL_SPARK_GRAVITY);
    sparkEmitter->SetCollisionDamped(METAL_SPARK_DAMPEN);
    sparkEmitter->GetBinding().SetBBox(offset - Vector(32, 32, 32), offset + Vector(32, 32, 32));

    int	numSparks = random->RandomInt(4, 8) * (iScale * 2);
    numSparks = (int) (0.5f + (float) numSparks * g_pParticleSystemMgr->ParticleThrottleScaling());

    if (g_Material_Spark == NULL)
    {
        g_Material_Spark = sparkEmitter->GetPMaterial("effects/spark");
    }

    TrailParticle	*pParticle;
    Vector	dir;
    float	length = 0.1f;

    //Dump out sparks
    for (int i = 0; i < numSparks; i++)
    {
        pParticle = (TrailParticle *) sparkEmitter->AddParticle(sizeof(TrailParticle), g_Material_Spark, offset);

        if (pParticle == NULL)
            return;

        pParticle->m_flLifetime = 0.0f;

        if (iScale > 1 && i % 3 == 0)
        {
            // Every third spark goes flying far if we're having a big batch of sparks.
            pParticle->m_flDieTime = random->RandomFloat(0.15f, 0.25f);
        }
        else
        {
            pParticle->m_flDieTime = random->RandomFloat(0.05f, 0.1f);
        }

        float	spreadOfs = random->RandomFloat(0.0f, 2.0f);

        dir[0] = direction[0] + random->RandomFloat(-(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs));
        dir[1] = direction[1] + random->RandomFloat(-(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs));
        dir[2] = direction[2] + random->RandomFloat(-(METAL_SPARK_SPREAD*spreadOfs), (METAL_SPARK_SPREAD*spreadOfs));

        VectorNormalize(dir);

        pParticle->m_flWidth = random->RandomFloat(1.0f, 4.0f);
        pParticle->m_flLength = random->RandomFloat(length*0.25f, length);

        pParticle->m_vecVelocity = dir * random->RandomFloat((METAL_SPARK_MINSPEED*(2.0f - spreadOfs)), (METAL_SPARK_MAXSPEED*(2.0f - spreadOfs)));

        Color32Init(pParticle->m_color, 255, 255, 255, 255);
    }

    //
    // Impact point glow
    //

    FXQuadData_t data;

    data.SetMaterial("effects/yellowflare");
    data.SetColor(1.0f, 1.0f, 1.0f);
    data.SetOrigin(offset);
    data.SetNormal(surfaceNormal);
    data.SetAlpha(1.0f, 0.0f);
    data.SetLifeTime(0.1f);
    data.SetYaw(random->RandomInt(0, 360));

    int scale = random->RandomInt(24, 28);
    data.SetScale(scale, 0);

    FX_AddQuad(data);
}
Пример #14
0
void FX_PhaserAltFire( vec3_t start, vec3_t end, vec3_t normal, qboolean spark, qboolean impact, qboolean empty )
{
	float		scale = flrandom(13.0f, 17.0f), scale2 = flrandom(2.0f, 6.0f);
	vec3_t		vel, diff, end2;
	int			i = 0, sparks = 0;
	refEntity_t	beam;
	vec3_t		rgb = { 1,0.6,0.5}, rgb2={1,0.3,0};
	float		len;
	int color;

	VectorSubtract(end, start, diff);
	len = VectorNormalize(diff);

	color = 0xff * flrandom(0.75, 1.0);

	if (empty)
	{	// More faint and shaky line.
		scale *= flrandom(0.25,0.75);
	}

	if (len > PHASER_ALT_CONE_LEN)
	{	// Draw beam in two parts...

		// Draw main beam first.
		VectorMA(start, PHASER_ALT_CONE_LEN, diff, end2);

		// Draw starting cone
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( start, beam.origin);
		VectorCopy( end2, beam.oldorigin );
		beam.reType = RT_LINE2;
		if (empty)
		{
			beam.customShader = cgs.media.phaserAltEmptyShader;
		}
		else
		{
			beam.customShader = cgs.media.phaserAltShader;
		}
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = 0xff;
		beam.shaderRGBA[1] = 0xff*0.3;
		beam.shaderRGBA[2] = 0;
		beam.shaderRGBA[3] = 0xff;
		beam.data.line.width = scale*0.1;
		beam.data.line.width2 = scale;
		beam.data.line.stscale = 1.0;
		trap_R_AddRefEntityToScene( &beam );

		// Draw big thick normal beam for the rest.
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( end2, beam.oldorigin);
		VectorCopy( end, beam.origin );
		beam.reType = RT_LINE;
		if (empty)
		{
			beam.customShader = cgs.media.phaserAltEmptyShader;
		}
		else
		{
			beam.customShader = cgs.media.phaserAltShader;
		}
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = 0xff;
		beam.shaderRGBA[1] = 0xff*0.3;
		beam.shaderRGBA[2] = 0;
		beam.shaderRGBA[3] = 0xff;
		beam.data.line.width = scale;
		beam.data.line.stscale = 1.0;
		trap_R_AddRefEntityToScene( &beam );

		// Draw beam core, all one bit.
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( start, beam.origin);
		VectorCopy( end, beam.oldorigin );
		beam.reType = RT_LINE2;
		beam.customShader = cgs.media.phaserShader;
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = color*0.75f;
		beam.shaderRGBA[1] = 0xff*0.5f;
		beam.shaderRGBA[2] = 0xff*0.5f;
		beam.shaderRGBA[3] = 0xff;
		beam.data.line.width = scale2*0.2;
		beam.data.line.width2 = scale2;
		beam.data.line.stscale = 1.0;
		trap_R_AddRefEntityToScene( &beam );
	}
	else
	{	// Draw beam in two parts...
		// Draw beam first.
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( start, beam.origin);
		VectorCopy( end, beam.oldorigin );
		beam.reType = RT_LINE2;
		beam.customShader = cgs.media.phaserAltShader;
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = 0xff;
		beam.shaderRGBA[1] = 0xff*0.3;
		beam.shaderRGBA[2] = 0;
		beam.shaderRGBA[3] = 0xff;
		beam.data.line.width = scale*0.1;
		beam.data.line.width2 = scale;
		beam.data.line.stscale = 1.0;
		trap_R_AddRefEntityToScene( &beam );

		// just one beam is never enough
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( start, beam.origin);
		VectorCopy( end, beam.oldorigin );
		beam.reType = RT_LINE2;
		beam.customShader = cgs.media.phaserShader;
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = color*0.75f;
		beam.shaderRGBA[1] = 0xff*0.5f;
		beam.shaderRGBA[2] = 0xff*0.5f;
		beam.shaderRGBA[3] = 0xff;
		beam.data.line.width = scale2*0.2;
		beam.data.line.width2 = scale2;
		beam.data.line.stscale = 1.0;
		trap_R_AddRefEntityToScene( &beam );
	}
	

	// Phaser beam
//	FX_AddLine( start, end, 1.0f, scale, 0.0f, 0.9f, 0.9f, 2, cgs.media.phaserShader );
//	FX_AddLine( start, end, 1.0f, scale * 0.5f, 0.0f, 0.8f, 0.8f, 2, cgs.media.phaserShader );
	
	// Per frame impact mark
	FX_AddQuad( end, normal, random() * 1.5 + 1.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.sparkShader );
	FX_AddQuad( end, normal, random() * 5 + 2.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.yellowParticleShader );

	// Multi frame impacts--never do this when it hits a player because it will just look stupid
	if ( impact )
	{
		FX_AddQuad2( end, normal, random() * 2.0 + 5.0f, 2.5f, 0.6f, 0.0f, rgb, rgb2, 0.0f, 500 + random() * 200, 
					cgs.media.sunnyFlareShader );

		CG_ImpactMark( cgs.media.scavMarkShader, end, normal, random()*360, 1,1,1,0.1, qfalse, 
					random() + 6.0, qfalse );
	}

	// "Fun" sparks
	if ( spark )
	{
		// kef -- fixme. dunno what the deal is with this velocity vector
		VectorClear(vel);
		sparks = (rand() & 3) + 1;

		// Set random starting pos...
		end2[0] = flrandom(-1.0, 1.0) + end[0];
		end2[1] = flrandom(-1.0, 1.0) + end[1];
		end2[2] = flrandom(-1.0, 1.0) + end[2];
		for( i = 0; i < sparks; i++ )
		{	
			scale = 0.5f + (random() * 0.5);
			FXE_Spray( normal, 200, 75, 0.8f, /*1024*/vel);
			FX_AddTrail2(	end2, vel, qfalse,
							8.0f, -8.0f,
							scale, -scale, 0.5f, 0.0f, rgb, rgb2, 0.4f, 500.0f, cgs.media.sparkShader );
		}

		VectorMA(end, -8, diff, end2);
		// Add a hit sprite over everything...
		memset( &beam, 0, sizeof( beam ) );
		VectorCopy( end2, beam.origin);
		beam.reType = RT_SPRITE;
		beam.customShader = cgs.media.sunnyFlareShader;
		AxisClear( beam.axis );
		beam.shaderRGBA[0] = 0xff*1.0f;
		beam.shaderRGBA[1] = 0xff*0.9f;
		beam.shaderRGBA[2] = 0xff*0.8f;
		beam.shaderRGBA[3] = 0xff;
		beam.data.sprite.radius = random()*2.0 + 9.0;
		trap_R_AddRefEntityToScene( &beam );
	}
}
Пример #15
0
void FX_EnergySplash(const Vector &pos, const Vector &normal, int nFlags)
{
    VPROF_BUDGET("FX_EnergySplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING);
    Vector	offset = pos + (normal * 2.0f);

    // Quick flash
    FX_AddQuad(pos,
        normal,
        64.0f,
        0,
        0.75f,
        1.0f,
        0.0f,
        0.4f,
        random->RandomInt(0, 360),
        0,
        Vector(1.0f, 1.0f, 1.0f),
        0.25f,
        "effects/combinemuzzle1_nocull",
        (FXQUAD_BIAS_SCALE | FXQUAD_BIAS_ALPHA));

    // Lingering burn
    FX_AddQuad(pos,
        normal,
        16,
        32,
        0.75f,
        1.0f,
        0.0f,
        0.4f,
        random->RandomInt(0, 360),
        0,
        Vector(1.0f, 1.0f, 1.0f),
        0.5f,
        "effects/combinemuzzle2_nocull",
        (FXQUAD_BIAS_SCALE | FXQUAD_BIAS_ALPHA));

    SimpleParticle *sParticle;

    CSmartPtr<CSimpleEmitter> pEmitter;

    pEmitter = CSimpleEmitter::Create("C_EntityDissolve");
    pEmitter->SetSortOrigin(pos);

    if (g_Material_Spark == NULL)
    {
        g_Material_Spark = pEmitter->GetPMaterial("effects/spark");
    }

    // Anime ground effects
    for (int j = 0; j < 8; j++)
    {
        offset.x = random->RandomFloat(-8.0f, 8.0f);
        offset.y = random->RandomFloat(-8.0f, 8.0f);
        offset.z = random->RandomFloat(0.0f, 4.0f);

        offset += pos;

        sParticle = (SimpleParticle *) pEmitter->AddParticle(sizeof(SimpleParticle), g_Material_Spark, offset);

        if (sParticle == NULL)
            return;

        sParticle->m_vecVelocity = Vector(Helper_RandomFloat(-4.0f, 4.0f), Helper_RandomFloat(-4.0f, 4.0f), Helper_RandomFloat(16.0f, 64.0f));

        sParticle->m_uchStartSize = random->RandomFloat(2, 4);

        sParticle->m_flDieTime = random->RandomFloat(0.4f, 0.6f);

        sParticle->m_flLifetime = 0.0f;

        sParticle->m_flRoll = Helper_RandomInt(0, 360);

        float alpha = 255;

        sParticle->m_flRollDelta = Helper_RandomFloat(-4.0f, 4.0f);
        sParticle->m_uchColor[0] = alpha;
        sParticle->m_uchColor[1] = alpha;
        sParticle->m_uchColor[2] = alpha;
        sParticle->m_uchStartAlpha = alpha;
        sParticle->m_uchEndAlpha = 0;
        sParticle->m_uchEndSize = 0;
    }
}
Пример #16
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &data - 
//-----------------------------------------------------------------------------
void AR2ExplosionCallback( const CEffectData &data )
{
	float lifetime = random->RandomFloat( 0.4f, 0.75f );

	// Ground splash
	FX_AddQuad( data.m_vOrigin, 
				data.m_vNormal, 
				data.m_flRadius, 
				data.m_flRadius * 4.0f,
				0.85f, 
				1.0f,
				0.0f,
				0.25f,
				random->RandomInt( 0, 360 ), 
				random->RandomFloat( -4, 4 ), 
				Vector( 1.0f, 1.0f, 1.0f ), 
				lifetime,
				"effects/combinemuzzle1",
				(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );

	Vector	vRight, vUp;
	VectorVectors( data.m_vNormal, vRight, vUp );

	Vector	start, end;
	
	float radius = data.m_flRadius * 0.15f;

	// Base vertical shaft
	FXLineData_t lineData;

	start = data.m_vOrigin;
	end = start + ( data.m_vNormal * random->RandomFloat( radius*2.0f, radius*4.0f ) );

	lineData.m_flDieTime = lifetime;
	
	lineData.m_flStartAlpha= 1.0f;
	lineData.m_flEndAlpha = 0.0f;
	
	lineData.m_flStartScale = radius*4;
	lineData.m_flEndScale = radius*5; 

	lineData.m_pMaterial = materials->FindMaterial( "effects/ar2ground2", 0, 0 );

	lineData.m_vecStart = start;
	lineData.m_vecStartVelocity = vec3_origin;

	lineData.m_vecEnd = end;
	lineData.m_vecEndVelocity = data.m_vNormal * random->RandomFloat( 200, 350 );

	FX_AddLine( lineData );

	// Inner filler shaft
	start = data.m_vOrigin;
	end = start + ( data.m_vNormal * random->RandomFloat( 16, radius*0.25f ) );

	lineData.m_flDieTime = lifetime - 0.1f;
	
	lineData.m_flStartAlpha= 1.0f;
	lineData.m_flEndAlpha = 0.0f;
	
	lineData.m_flStartScale = radius*2;
	lineData.m_flEndScale = radius*4; 

	lineData.m_pMaterial = materials->FindMaterial( "effects/ar2ground2", 0, 0 );

	lineData.m_vecStart = start;
	lineData.m_vecStartVelocity = vec3_origin;

	lineData.m_vecEnd = end;
	lineData.m_vecEndVelocity = data.m_vNormal * random->RandomFloat( 64, 128 );

	FX_AddLine( lineData );
}
Пример #17
0
//------------------------------------------------
void FX_ParasiteAcidHitWall( vec3_t origin, vec3_t dir )
//------------------------------------------------
{
	FXTrail		*particle;
	float		detail;
	vec3_t		rgb={0.2f,0.8f,0.0f};
	int			i;

	// Spawn some smoke from the acid burn
	for ( i = 0; i < 4; i ++ )
	{
		CG_Smoke( origin, dir, random() * 4.0f + 8.0f, random() * 16.0f + 2.0f, cgs.media.steamShader );
	}

	FX_AddQuad( origin, dir, NULL, NULL, 4.0, 6.0, 0.5, 0.0, rgb, rgb, 0.0, 0.0, 0.0, 550, cgs.media.waterDropShader );

	// Leave a melted spot
	CG_ImpactMark( cgs.media.bulletmarksShader, origin, dir, random()*360, 1,1,1,0.2f, qfalse, 
					random() * 3.0f + 8.0, qfalse );

	//Sound
	cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cg_weapons[WP_PARASITE].missileHitSound );

	// See if it's worth doing a splash
	detail = FX_DetailLevel( origin, 16, 400 );
	if (detail == 0)
		return;

	// splash the acid
	for ( i = 0; i < 10; i++ )
	{	
		particle = FX_AddTrail( origin, NULL, NULL, 3.0f, -1.0f, 2.0, -1.0,
								0.3f, 0.1f, rgb, rgb, 0.4f, 500.0f, cgs.media.waterDropShader, rand() & FXF_BOUNCE );

		if ( particle != NULL )
		{
			FXE_Spray( dir, 80, 100, 0.95f, 512, (FXPrimitive *) particle );
		}
	}

	// Make a real splash

	vec3_t		org;
	FXSprite	*fx;
	vec3_t		moveDir;
	vec3_t		accel = { 0, 0, -400 };

	for ( i = 0; i < 6; i++ )
	{
		VectorSet( org,
					origin[0] + crandom() * 2.5f,
					origin[1] + crandom() * 2.5f,
					origin[2] + crandom() * 2.5f );
	
		for ( int j = 0; j < 3; j++ )
		{
			moveDir[j] = crandom() * 55.0;
		}
		moveDir[2] += 120.0f;

		VectorSet( rgb,
					random() * 0.3f + 0.2f,
					random() * 0.4f + 0.5f,
					random() * 0.2f + 0.05f );


		fx = FX_AddSprite( org, moveDir, accel, 2.0f + ( random() * 1.0f ), -2.0f, 
					1.0f, 1.0f, 
					rgb, rgb, 
					0, 0.0f, 
					400 + random() * 700, 
					cgs.media.spooShader );

		if ( fx == NULL )
			return;

		fx->SetRoll( 0 );
	}

}
Пример #18
0
void FX_ProtonExplosion( vec3_t end, vec3_t dir )
{
	vec3_t	org;

	// Move me away from the wall a bit so that I don't z-buffer into it
	VectorMA( end, 0.5, dir, org );

	// Expanding rings
//	FX_AddQuad( org, dir, NULL, NULL, 1, 24, 0.8f, 0.2f, random() * 360, 360, 0, 400, cgs.media.protonRingShader );
//	FX_AddQuad( org, dir, NULL, NULL, 1, 60, 0.8f, 0.2f, random() * 360, -360, 0, 300, cgs.media.protonRingShader );

	// Impact effect
//	FX_AddQuad( org, dir, NULL, NULL, 7, 35, 1.0, 0.0, random() * 360, 0, 0, 500, cgs.media.blueParticleShader );
//	FX_AddQuad( org, dir, NULL, NULL, 5, 25, 1.0, 0.0, random() * 360, 0, 0, 420, cgs.media.ltblueParticleShader );

	// Test of using the ripple shader......
	FX_AddQuad( org, dir, NULL, NULL, 13, 16, 1.0f, 0.1f, random() * 360, 360, 0, 400, cgs.media.rippleShader );
	FX_AddQuad( org, dir, NULL, NULL, 9, 20, 0.8f, 0.1f, random() * 360, -360, 0, 300, cgs.media.rippleShader );
	FX_AddQuad( org, dir, NULL, NULL, 20, 8, 1.0f, 0.1f, random() * 360, 0, 0, 300, cgs.media.rippleShader );

	FX_AddQuad( org, dir, NULL, NULL, 30, -20, 1.0f, 0.8f, random() * 360, 0, 0, 300, cgs.media.waterDropShader );

	
/*	
	localEntity_t	*le;
	FXTrail			*particle;
	vec3_t			direction, new_org;
	vec3_t			velocity		=	{ 0, 0, 8 };
	float			scale, dscale;

	int				i, numSparks;

	//Sparks
	numSparks = 4 + (random() * 4.0f);

	for ( i = 0; i < numSparks; i++ )
	{	
		scale = 0.25f + (random() * 2.0f);
		dscale = -scale * 0.5f;

		particle = FX_AddTrail( origin,
								NULL,
								NULL,
								16.0f,
								-32.0f,
								scale,
								-scale,
								1.0f,
								1.0f,
								0.25f,
								2000.0f,
								cgs.media.sparkShader,
								rand() & FXF_BOUNCE );

		if ( particle == NULL )
			return;

		FXE_Spray( normal, 200, 50, 0.5f, 512, (FXPrimitive *) particle );
	}

	// Smoke puff
	VectorMA( origin, 8, normal, new_org );

	FX_AddSprite( new_org, 
					velocity, NULL, 
					16.0f, 16.0f,
					1.0f, 0.0f,
					random()*45.0f,
					0.0f,
					1000.0f,
					cgs.media.steamShader );

	scale = 0.4f + ( random() * 0.2f);



	//Orient the explosions to face the camera
	VectorSubtract( cg.refdef.vieworg, origin, direction );
	VectorNormalize( direction );


	// Add in the explosion and tag it with a light
	le = CG_MakeExplosion( origin, direction, cgs.media.explosionModel, 6, cgs.media.electricalExplosionSlowShader, 475, qfalse, scale );
	le->light = 150;
	le->refEntity.renderfx |= RF_NOSHADOW;
	VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f );

	// Scorch mark
	CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 4, qfalse );

	CG_ExplosionEffects( origin, 1.0f, 150 );
	*/
}
Пример #19
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
}
Пример #20
0
void FX_DisruptorWeaponHitWall( vec3_t origin, vec3_t dir, int size )
{
	vec3_t			vel, /*accel,*/ hitpos, direction, org;
	//int				i, t;
	weaponInfo_t	*weaponInfo = &cg_weapons[WP_10];

	CG_InitLensFlare( origin, 
					375, 375,
					colorTable[CT_GREEN], 1.2, 2.0, 1600, 200,
					colorTable[CT_GREEN], 1600, 200, 800, 20,  qtrue, 
					0, 0, qfalse, qtrue, 
					qfalse, 1.0, cg.time, 0, 0, 200);

	// Generate "crawling" electricity		// eh, don't it doesn't look that great.
	FX_DisruptorDischarge( origin, dir, NUM_DISCHARGES, DISCHARGE_DIST, DISCHARGE_SIDE_DIST );

	VectorMA(origin, size, dir, hitpos);

	// Set an oriented residual glow effect
	FX_AddQuad( hitpos, dir, size * size * 15.0f, -150.0f, 
				1.0f, 0.0f, 0, 300, cgs.media.greenParticleShader );

	CG_ImpactMark( cgs.media.scavMarkShader, origin, dir, random()*360, 1,1,1,0.6, qfalse, 
					size * 12 + 1, qfalse );

	FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, 
				1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleShader );

/*	FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, 
				1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleStreakShader ); */

	FX_AddSprite( hitpos, NULL, qfalse, size * size * 25.0f, -150.0f, 
				1.0f, 0.0f, 0.0f, 0, 400, cgs.media.greenParticleStreakShader );

	VectorSubtract( cg.refdef.vieworg, origin, direction );
	VectorNormalize( direction );

	VectorMA( origin, 12, direction, org );
	VectorMA( org, 8, dir, direction );
	VectorSet(vel, 0, 0, 32 ); //8

	FX_AddSprite( origin, 
						vel, qfalse, 
						random() * 4 + 2, 12,
						0.6 + random() * 0.4, 0.0,
						random() * 180, 
						0.0, 
						random() * 200 + 1200, //300
						cgs.media.steamShader );

	//FX_AddSprite(

	// Only play the impact sound and throw off the purple particles when it's the main projectile
/*	if ( size < 3 )
		return;

	for ( i = 0; i < 4; i++ )
	{
		for ( t = 0; t < 3; t++ )
			vel[t] = ( dir[t] + crandom() * 0.9 ) * ( random() * 100 + 250 );

		VectorScale( vel, -2.2, accel );
		FX_AddSprite( hitpos, vel, qfalse, random() * 8 + 8, 0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.purpleParticleShader );

	}*/
	trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound );
}