/* =============== ParticleEffect PARTICLE_EFFECT on server =============== */ void CL_RunParticleEffect( const vec3_t org, const vec3_t dir, int color, int count ) { particle_t *p; int i, j; if( count == 1024 ) { // Quake hack: count == 255 it's a RocketExplode CL_ParticleExplosion( org ); return; } for( i = 0; i < count; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += Com_RandomFloat( 0.0f, 0.5f ); p->color = ( color & ~7 ) + Com_RandomLong( 0, 8 ); p->type = pt_slowgrav; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -8, 8 ); p->vel[j] = dir[j] * 15; } } }
/* =============== CL_ParticleExplosion2 =============== */ void CL_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength ) { int i, j; int colorMod = 0; particle_t *p; int hSound; if( !org ) return; hSound = S_RegisterSound( "weapons/explode3.wav" ); S_StartSound( org, 0, CHAN_AUTO, hSound, VOL_NORM, ATTN_NORM, PITCH_NORM, 0 ); for( i = 0; i < 512; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += 0.3f; p->color = colorStart + ( colorMod % colorLength ); colorMod++; p->type = pt_blob; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -16.0f, 16.0f ); p->vel[j] = Com_RandomFloat( -256.0f, 256.0f ); } } }
/* =============== CL_TeleportSplash =============== */ void CL_TeleportSplash( const vec3_t org ) { particle_t *p; vec3_t dir; int i, j, k; for( i = -16; i < 16; i += 4 ) { for( j = -16; j < 16; j += 4 ) { for( k = -24; k < 32; k += 4 ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += Com_RandomFloat( 0.2f, 0.36f ); p->color = Com_RandomLong( 7, 14 ); p->type = pt_slowgrav; dir[0] = j * 8; dir[1] = i * 8; dir[2] = k * 8; p->org[0] = org[0] + i + Com_RandomFloat( -4.0f, 4.0f ); p->org[1] = org[1] + j + Com_RandomFloat( -4.0f, 4.0f ); p->org[2] = org[2] + k + Com_RandomFloat( -4.0f, 4.0f ); VectorNormalize( dir ); VectorScale( dir, Com_RandomLong( 50, 114 ), p->vel ); } } } }
/* =============== CL_SparkShower Creates 8 random tracers =============== */ void CL_SparkShower( const vec3_t org ) { vec3_t pos, dir; model_t *pmodel; float vel; int i; // randomize position pos[0] = org[0] + Com_RandomFloat( -2.0f, 2.0f ); pos[1] = org[1] + Com_RandomFloat( -2.0f, 2.0f ); pos[2] = org[2] + Com_RandomFloat( -2.0f, 2.0f ); pmodel = Mod_Handle( CL_FindModelIndex( "sprites/richo1.spr" )); CL_RicochetSprite( pos, pmodel, 0.0f, Com_RandomFloat( 0.4, 0.6f )); // create a 8 random spakle tracers for( i = 0; i < 8; i++ ) { dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); vel = Com_RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED ); CL_SparkleTracer( pos, dir, vel ); } }
/* =============== CL_ParticleBurst =============== */ void CL_ParticleBurst( const vec3_t org, int size, int color, float life ) { particle_t *p; float vel; vec3_t dir; int i, j, k; for( i = -size; i < size; i++ ) { for( j = -size; j < size; j++ ) { for( k = 0; k < 1; k++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += life + Com_RandomFloat( 0.0f, 0.1f ); p->color = color; p->type = pt_slowgrav; dir[0] = j * 8 + Com_RandomLong( 0, 8 ); dir[1] = i * 8 + Com_RandomLong( 0, 8 ); dir[2] = 256; p->org[0] = org[0] + dir[0]; p->org[1] = org[1] + dir[1]; p->org[2] = org[2] + Com_RandomLong( 0, 64 ); VectorNormalize( dir ); vel = 50 + Com_RandomLong( 0, 64 ); VectorScale( dir, vel, p->vel ); } } } }
/* =============== CL_LavaSplash =============== */ void CL_LavaSplash( const vec3_t org ) { particle_t *p; float vel; vec3_t dir; int i, j, k; for( i = -16; i < 16; i++ ) { for( j = -16; j <16; j++ ) { for( k = 0; k < 1; k++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += 2.0f + Com_RandomFloat( 0.0f, 0.65f ); p->color = 224 + Com_RandomLong( 0, 8 ); p->type = pt_slowgrav; dir[0] = j * 8 + Com_RandomLong( 0, 8 ); dir[1] = i * 8 + Com_RandomLong( 0, 8 ); dir[2] = 256; p->org[0] = org[0] + dir[0]; p->org[1] = org[1] + dir[1]; p->org[2] = org[2] + Com_RandomLong( 0, 64 ); VectorNormalize( dir ); vel = 50 + Com_RandomLong( 0, 64 ); VectorScale( dir, vel, p->vel ); } } } }
/* =============== CL_TracerEffect =============== */ void CL_TracerEffect( const vec3_t start, const vec3_t end ) { particle_t *p; byte *color; vec3_t dir; float life, dist; p = CL_AllocParticle( CL_BulletTracerDraw ); if( !p ) return; // get out shot direction and length VectorSubtract( end, start, dir ); VectorCopy( dir, p->vel ); dist = VectorNormalizeLength( dir ); // don't make small tracers if( dist <= traceroffset->value ) return; p->ramp = Com_RandomFloat( 200.0f, 256.0f ) * tracerlength->value; color = gTracerColors[4]; life = ( dist + p->ramp ) / ( max( 1.0f, tracerspeed->value )); p->color = CL_LookupColor( color[0], color[1], color[2] ); VectorCopy( start, p->org ); p->type = pt_tracer; p->die += life; }
/* =============== CL_SparkleTracer =============== */ void CL_SparkleTracer( const vec3_t pos, const vec3_t dir, float vel ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_SparkTracerDraw ); if( !p ) return; color = gTracerColors[5]; // Yellow-Orange VectorCopy( pos, p->org ); p->die += Com_RandomFloat( 0.45f, 0.7f ); p->color = CL_LookupColor( color[0], color[1], color[2] ); p->ramp = Com_RandomFloat( 0.07f, 0.08f ); // ramp used as tracer length p->type = pt_tracer; VectorScale( dir, vel, p->vel ); }
/* =============== CL_FlickerParticles =============== */ void CL_FlickerParticles( const vec3_t org ) { particle_t *p; int i, j; for( i = 0; i < 16; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += Com_RandomFloat( 0.5f, 2.0f ); p->type = pt_blob; for( j = 0; j < 3; j++ ) p->org[j] = org[j] + Com_RandomFloat( -32.0f, 32.0f ); p->vel[2] = Com_RandomFloat( 64.0f, 100.0f ); } }
/* =============== CL_BlobExplosion =============== */ void CL_BlobExplosion( const vec3_t org ) { particle_t *p; int i, j; int hSound; if( !org ) return; hSound = S_RegisterSound( "weapons/explode3.wav" ); S_StartSound( org, 0, CHAN_AUTO, hSound, VOL_NORM, ATTN_NORM, PITCH_NORM, 0 ); for( i = 0; i < 1024; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += 1.0f + Com_RandomFloat( 0, 0.4f ); if( i & 1 ) { p->type = pt_explode; p->color = 66 + rand() % 6; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -16.0f, 16.0f ); p->vel[j] = Com_RandomFloat( -256.0f, 256.0f ); } } else { p->type = pt_explode2; p->color = 150 + rand() % 6; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -16.0f, 16.0f ); p->vel[j] = Com_RandomFloat( -256.0f, 256.0f ); } } } }
/* =============== CL_Blood particle spray =============== */ void CL_Blood( const vec3_t org, const vec3_t dir, int pcolor, int speed ) { particle_t *p; int i, j; for( i = 0; i < speed * 20; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += Com_RandomFloat( 0.1f, 0.5f ); p->type = pt_slowgrav; p->color = pcolor; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -8.0f, 8.0f ); p->vel[j] = dir[j] * speed; } } }
/* =============== CL_Implosion =============== */ void CL_Implosion( const vec3_t end, float radius, int count, float life ) { particle_t *p; float vel, radius2; vec3_t dir, m_vecPos; int i, colorIndex; colorIndex = CL_LookupColor( gTracerColors[5][0], gTracerColors[5][1], gTracerColors[5][2] ); for( i = 0; i < count; i++ ) { p = CL_AllocParticle( CL_TracerImplosion ); if( !p ) return; dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); radius2 = Com_RandomFloat( radius * 0.9f, radius * 1.1f ); VectorNormalize( dir ); VectorMA( end, -radius2, dir, m_vecPos ); // velocity based on how far particle has to travel away from org if( life ) vel = (radius2 / life); else vel = Com_RandomFloat( radius2 * 0.5f, radius2 * 1.5f ); VectorCopy( m_vecPos, p->org ); p->color = colorIndex; p->ramp = (vel / radius2) * 0.1f; // length based on velocity p->ramp = bound( 0.1f, p->ramp, 1.0f ); p->type = pt_tracer; VectorScale( dir, vel, p->vel ); // die right when you get there p->die += ( life != 0.0f ) ? life : ( radius2 / vel ); } }
/* =============== CL_StreakTracer =============== */ void CL_StreakTracer( const vec3_t pos, const vec3_t velocity, int colorIndex ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_SparkTracerDraw ); if( !p ) return; if( colorIndex > ( sizeof( gTracerColors ) / sizeof( gTracerColors[0] ))) { p->color = bound( 0, colorIndex, 255 ); } else { color = gTracerColors[colorIndex]; p->color = CL_LookupColor( color[0], color[1], color[2] ); } p->die += Com_RandomFloat( 0.5f, 1.0f ); VectorCopy( velocity, p->vel ); VectorCopy( pos, p->org ); p->ramp = Com_RandomFloat( 0.05f, 0.08f ); p->type = pt_tracer; }
/* =============== CL_BulletImpactParticles =============== */ void CL_BulletImpactParticles( const vec3_t org ) { particle_t *p; vec3_t pos, dir; float vel; int i, j; // do sparks // randomize position pos[0] = org[0] + Com_RandomFloat( -2.0f, 2.0f ); pos[1] = org[1] + Com_RandomFloat( -2.0f, 2.0f ); pos[2] = org[2] + Com_RandomFloat( -2.0f, 2.0f ); // create a 8 random spakle tracers for( i = 0; i < 8; i++ ) { dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); vel = Com_RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED ); CL_SparkleTracer( pos, dir, vel ); } for( i = 0; i < 12; i++ ) { p = CL_AllocParticle( NULL ); if( !p ) return; p->die += 1.0f; p->color = 0; // black p->type = pt_grav; for( j = 0; j < 3; j++ ) { p->org[j] = org[j] + Com_RandomFloat( -2.0f, 3.0f ); p->vel[j] = Com_RandomFloat( -70.0f, 70.0f ); } } }
/* =============== CL_TracerParticles allow more customization =============== */ particle_t *CL_TracerParticles( float *org, float *vel, float life ) { particle_t *p; byte *color; p = CL_AllocParticle( CL_BulletTracerDraw ); if( !p ) return NULL; p->ramp = Com_RandomFloat( 200.0f, 256.0f ) * tracerlength->value; color = gTracerColors[4]; p->color = CL_LookupColor( color[0], color[1], color[2] ); VectorCopy( org, p->org ); VectorCopy( vel, p->vel ); p->type = pt_tracer; p->die += life; return p; }
/* =============== CL_RocketTrail =============== */ void CL_RocketTrail( vec3_t start, vec3_t end, int type ) { vec3_t vec; float len; particle_t *p; int j, dec; static int tracercount; VectorSubtract( end, start, vec ); len = VectorNormalizeLength( vec ); if( type < 128 ) { dec = 3; } else { dec = 1; type -= 128; } while( len > 0 ) { len -= dec; p = CL_AllocParticle( NULL ); if( !p ) return; p->die += 2.0f; switch( type ) { case 0: // rocket trail p->ramp = Com_RandomLong( 0, 4 ); p->color = ramp3[(int)p->ramp]; p->type = pt_fire; for( j = 0; j < 3; j++ ) p->org[j] = start[j] + ((rand() % 6 ) - 3 ); break; case 1: // smoke smoke p->ramp = Com_RandomLong( 2, 6 ); p->color = ramp3[(int)p->ramp]; p->type = pt_fire; for( j = 0; j < 3; j++ ) p->org[j] = start[j] + ((rand() % 6 ) - 3 ); break; case 2: // blood p->type = pt_grav; p->color = Com_RandomLong( 67, 71 ); for( j = 0; j < 3; j++ ) p->org[j] = start[j] + ((rand() % 6 ) - 3 ); break; case 3: case 5: // tracer p->die += 0.5f; p->type = pt_static; if( type == 3 ) p->color = 52 + (( tracercount & 4 )<<1 ); else p->color = 230 + (( tracercount & 4 )<<1 ); tracercount++; VectorCopy( start, p->org ); if( tracercount & 1 ) { p->vel[0] = 30 * vec[1]; p->vel[1] = 30 * -vec[0]; } else { p->vel[0] = 30 * -vec[1]; p->vel[1] = 30 * vec[0]; } break; case 4: // slight blood p->type = pt_grav; p->color = Com_RandomLong( 67, 71 ); for( j = 0; j < 3; j++ ) p->org[j] = start[j] + Com_RandomFloat( -3.0f, 3.0f ); len -= 3; break; case 6: // voor trail p->color = Com_RandomLong( 152, 156 ); p->type = pt_static; p->die += 0.3f; for( j = 0; j < 3; j++ ) p->org[j] = start[j] + Com_RandomFloat( -16.0f, 16.0f ); break; } VectorAdd( start, vec, start ); } }
/* =============== CL_BulletImpactParticles =============== */ void CL_BulletImpactParticles( const vec3_t org ) { particle_t *p; vec3_t pos, dir; float vel; int i, j; // do sparks // randomize position pos[0] = org[0] + Com_RandomFloat( -2.0f, 2.0f ); pos[1] = org[1] + Com_RandomFloat( -2.0f, 2.0f ); pos[2] = org[2] + Com_RandomFloat( -2.0f, 2.0f ); // create a 8 random spakle tracers for( i = 0; i < 8; i++ ) { dir[0] = Com_RandomFloat( -1.0f, 1.0f ); dir[1] = Com_RandomFloat( -1.0f, 1.0f ); dir[2] = Com_RandomFloat( -1.0f, 1.0f ); vel = Com_RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED ); CL_SparkleTracer( pos, dir, vel ); } if (r_oldparticles->integer == 1) { for (i = 0; i < 12; i++) { int greyColors; p = CL_AllocParticle(NULL); if (!p) return; p->die += 1.0f; // Randomly make each particle one of three colors: dark grey, medium grey or light grey. greyColors = (rand() % 3 + 1) * 32; p->color = CL_LookupColor(greyColors, greyColors, greyColors); p->type = pt_grav; for (j = 0; j < 3; j++) { p->org[j] = org[j] + Com_RandomFloat(-2.0f, 3.0f); p->vel[j] = Com_RandomFloat(-70.0f, 70.0f); } } } else { for (i = 0; i < 12; i++) { p = CL_AllocParticle(NULL); if (!p) return; p->die += 1.0f; p->color = 0; // black p->type = pt_grav; for (j = 0; j < 3; j++) { p->org[j] = org[j] + Com_RandomFloat(-2.0f, 3.0f); p->vel[j] = Com_RandomFloat(-70.0f, 70.0f); } } } }