rpg-x2/cgame/fx_compression.c
2011-06-01 14:20:56 +02:00

434 lines
11 KiB
C

//Compression rifle weapon effects
#include "cg_local.h"
#include "fx_local.h"
qboolean AltCompressionAftereffect(localEntity_t *le)
{
localEntity_t *cyl = NULL;
qhandle_t shader = cgs.media.compressionAltBlastShader;
float percentLife = 1.0 - (le->endTime - cg.time)*le->lifeRate;
float alpha = 0.6 - (0.6*percentLife);
float length = 20;
vec3_t vec2, dir2;
cyl = FX_AddCylinder( le->refEntity.origin,
le->data.spawner.dir,
length,// height,
0,// dheight,
10,//10+(30*(1-percentLife)),// scale,
210,// dscale,
10+(30*percentLife),// scale2,
210,// dscale2,
alpha,// startalpha,
0.0,// endalpha,
500,// killTime,
shader,
15);// bias );
cyl->leFlags |= LEF_ONE_FRAME;
VectorMA(le->refEntity.origin, length*2.0, le->data.spawner.dir, vec2);
VectorScale(le->data.spawner.dir, -1.0, dir2);
cyl = FX_AddCylinder( vec2,
dir2,
length,// height,
0,// dheight,
10,//10+(30*(1-percentLife)),// scale,
210,// dscale,
10+(30*percentLife),// scale2,
210,// dscale2,
alpha,// startalpha,
0.0,// endalpha,
500,// killTime,
shader,
15);// bias );
cyl->leFlags |= LEF_ONE_FRAME;
return qtrue;
}
/*
-------------------------
FX_CompressionShot
-------------------------
*/
#define MAXRANGE_CRIFLE 8192
void FX_CompressionShot( vec3_t start, vec3_t dir )
{
localEntity_t *le;
vec3_t end;
trace_t trace;
qboolean render_impact = qtrue;
centity_t *traceEnt = NULL;
int clientNum = -1;
VectorMA(start, MAXRANGE_CRIFLE, dir, end);
CG_Trace( &trace, start, NULL, NULL, end, 0, MASK_SHOT );
// draw the beam
le = FX_AddLine(start, trace.endpos, 1.0, 2.0, 0.0, 1.0, 1.0, 100.0, cgs.media.prifleBolt);
le->leFlags |= LEF_ONE_FRAME;
// draw an impact at the endpoint of the trace
// If the beam hits a skybox, etc. it would look foolish to add in an explosion
if ( trace.surfaceFlags & SURF_NOIMPACT )
{
render_impact = qfalse;
}
if ( render_impact )
{
traceEnt = &cg_entities[trace.entityNum];
clientNum = traceEnt->currentState.clientNum;
if ( (trace.entityNum != ENTITYNUM_WORLD) && (clientNum >= 0 || clientNum < MAX_CLIENTS) )
{
FX_CompressionHit(trace.endpos);
}
else
{
FX_CompressionExplosion(start, trace.endpos, trace.plane.normal, qfalse);
}
}
}
/*
-------------------------
FX_CompressionShot
-------------------------
*/
void FX_CompressionAltShot( vec3_t start, vec3_t dir )
{
vec3_t end, vel = {0,0,0};
trace_t trace;
qboolean render_impact = qtrue;
centity_t *traceEnt = NULL;
int clientNum = -1;
VectorMA(start, MAXRANGE_CRIFLE, dir, end);
CG_Trace( &trace, start, NULL, NULL, end, cg_entities[cg.predictedPlayerState.clientNum].currentState.number, MASK_SHOT );
// draw the beam
FX_AddLine( start, trace.endpos, 1.0f, 3.0f, 0.0f, 1.0f, 0.0f, 350/*125.0f*/, cgs.media.sparkShader );
FX_AddLine( start, trace.endpos, 1.0f, 6.0f, 20.0f, 0.6f, 0.0f, 800/*175.0f*/, cgs.media.phaserShader);//compressionAltBeamShader );
FX_AddSpawner( start, dir, vel, NULL, qfalse, 0,
0, 500, AltCompressionAftereffect, 10 );
// draw an impact at the endpoint of the trace
// If the beam hits a skybox, etc. it would look foolish to add in an explosion
if ( trace.surfaceFlags & SURF_NOIMPACT )
{
render_impact = qfalse;
}
if ( render_impact )
{
traceEnt = &cg_entities[trace.entityNum];
clientNum = traceEnt->currentState.clientNum;
if ( (trace.entityNum != ENTITYNUM_WORLD) && (clientNum >= 0 || clientNum < MAX_CLIENTS) )
{
FX_CompressionHit(trace.endpos);
}
else
{
FX_CompressionExplosion(start, trace.endpos, trace.plane.normal, qtrue);
}
}
}
/*
-------------------------
FX_CompressionExplosion
-------------------------
*/
void FX_CompressionExplosion( vec3_t start, vec3_t origin, vec3_t normal, qboolean altfire )
{
localEntity_t *le;
vec3_t dir;
vec3_t velocity; //, shot_dir;
vec3_t hitpos;
float scale, dscale;
int i, j, numSparks;
weaponInfo_t *weaponInfo = &cg_weapons[WP_COMPRESSION_RIFLE];
float distance;
vec3_t color = {0.7, 0.43, 0.44};
int size = 2;
//FX_CompressionHit( origin ); //TiM: let's test if the rifle doesn't make stuff explode when its shot :)
//return;
//Sparks
//TiM: Calc spark count off proximity to effect
VectorSubtract ( cg.refdef.vieworg, origin, dir );
distance = VectorNormalize( dir );
distance = 50 * ( 1.0f - (distance / 128) ) ;
distance = Com_Clamp( 25, 50, distance );
numSparks = distance + (random() * 4.0f); //4
if (altfire)
{
numSparks *= 1.5f;
}
for ( i = 0; i < numSparks; i++ )
{
scale = 10.0f + (random() * 1.0f); //.25
dscale = -scale;
//Randomize the direction
for (j = 0; j < 3; j ++ )
{
//if ( j !=5 )
//dir[j] = normal[j] + (0.75 * crandom());
//else
dir[j] = normal[j] + (-1 * crandom()); //0.75
}
VectorNormalize(dir);
//set the speed
VectorScale( dir, 200 + (50 * crandom()), velocity); //200
le = FX_AddTrail( origin,
velocity,
qtrue, //qtrue
12.0f,//4
-12.0f,//4
scale,
-scale,
1.0f,
1.0f,
0.5f,
1000.0f, //1000
cgs.media.orangeStarShader);
// FXE_Spray( normal, 200, 50, 0.4f, le);
}
VectorMA( origin, 8, normal, dir );
VectorSet(velocity, 0, 0, 8);
/*
FX_AddSprite( dir,
velocity,
qfalse,
(altfire?50.0f:32.0f),
16.0f,
1.0f,
0.0f,
random()*45.0f,
0.0f,
(altfire?1300.0f:1000.0f),
cgs.media.steamShader );
*/
//Orient the explosions to face the camera
VectorSubtract( cg.refdef.vieworg, origin, dir );
VectorNormalize( dir );
if (!altfire)
{
CG_InitLensFlare( origin,
350, 350,
color, 1.2, 2.0, 1600, 200,
color, 1600, 200, 800, 20, qtrue,
0, 0, qfalse, qtrue,
qfalse, 1.0, cg.time, 0, 0, 210);
VectorMA(origin, size, normal, hitpos);
FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f,
1.0f, 0.0f, 360*random(), 0, 400, cgs.media.liteRedParticleShader );
FX_AddSprite( hitpos, NULL, qfalse, size * size * 25.0f, -150.0f,
1.0f, 0.0f, 0.0f, 0, 400, cgs.media.liteRedParticleStreakShader );
le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader,
475, qfalse, 1.2f + ( crandom() * 0.3f), LEF_NONE);
le->light = 150;
le->refEntity.renderfx |= RF_NOSHADOW;
VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f );
CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 12, qfalse );
//Shake the camera
CG_ExplosionEffects( origin, 1, 200 );
}
else
{
le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader,
500, qfalse, 2.2f + ( crandom() * 0.4f), LEF_NONE);
le->light = 200;
le->refEntity.renderfx |= RF_NOSHADOW;
VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f );
CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 28, qfalse );
//Shake the camera
CG_ExplosionEffects( origin, 2, 240 );
}
// nice explosion sound at the point of impact
trap_S_StartSound(origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound);
}
/*
-------------------------
FX_CompressionHit
-------------------------
*/
void FX_CompressionHit( vec3_t origin )
{
FX_AddSprite( origin,
NULL,
qfalse,
32.0f,
-32.0f,
1.0f,
1.0f,
random()*360,
0.0f,
250.0f,
cgs.media.prifleImpactShader );
//FIXME: Play an impact sound with a body
// trap_S_StartSound (origin, NULL, 0, cgi_S_RegisterSound ("sound/weapons/prifle/fire.wav") );
}
void FX_PrifleBeamFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty )
{
refEntity_t beam;
sfxHandle_t sfx;
float size;
vec3_t velocity;
int sparks;
vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0};
//vec3_t rgb3 = { 1.0, 1.0, 1.0 };
sfx = 0;
// Draw beam first.
memset( &beam, 0, sizeof( beam ) );
VectorCopy( startpos, beam.origin);
VectorCopy( endpos, beam.oldorigin );
beam.reType = RT_LINE;
if (empty)
{
beam.customShader = cgs.media.phaserEmptyShader;
}
else
{
beam.customShader = cgs.media.prifleBeam;
}
AxisClear( beam.axis );
beam.shaderRGBA[0] = 0xff;
beam.shaderRGBA[1] = 0xff;
beam.shaderRGBA[2] = 0xff;
beam.shaderRGBA[3] = 0xff;
if (empty)
{
beam.data.line.width = 1.0f + ( crandom() * 0.6f );
}
else
{
beam.data.line.width = 2.5f + ( crandom() * 0.6f );
}
beam.data.line.stscale = 5.0;
trap_R_AddRefEntityToScene( &beam );
// Now draw the hit graphic
// no explosion at LG impact, it is added with the beam
if ( sfx )
{
Com_Printf("playing %s\n", "phaser sound");
trap_S_StartSound( endpos, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
}
//
// impact mark
//
if (impact)
{
if (!empty)
{ // normal.
CG_ImpactMark( cgs.media.scavMarkShader, endpos, normal, random()*360, 1,1,1,0.2, qfalse,
random() + 1, qfalse );
//VectorCopy( endpos, phaserFlare.worldCoord );
/*CG_InitLensFlare( endpos,
80,
80,
rgb,
1.2,
1.5,
1600,
200,
colorTable[CT_BLACK],
1600,
200,
80,
5,
qfalse,
5,
40,
qfalse,
qfalse,
qfalse,
1.0,
1.0,
200.0,
200.0,
200.0 );*/
//CG_InitLensFlare( endpos,
// 30, 30,
// rgb, 1.2, 2.0, 1600, 200,
// colorTable[CT_BLACK], 1600, 200, 410, 15, qfalse,
// 0, 0, qfalse, qtrue,
// qfalse, 1.0, cg.time, 0, 0, 50);
//TiM : Add your basic cheesy 'seen-way-too-much-in-movies-these-days' anamorphic lens streak :)
//CG_DrawLensFlare( &phaserFlare );
//FX_AddSprite( endpos, NULL, qfalse, random() * 1.25 + 5.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 50.0, cgs.media.blueParticleStreakShader ); //1.5f
//FX_AddQuad2( endpos, normal, random() * 1.25 + 8.0f, 0.0f, 1.0f, 1.0f, rgb3, rgb3, 270, 50.0, cgs.media.blueParticleStreakShader );
//eh... looked bad :P
FX_AddQuad2( endpos, normal, random() * 1.25 + 1.5f, 0.0f, 1.0f, 0.0f, rgb, rgb2, rand() % 360, 500 + random() * 200,
cgs.media.sunnyFlareShader );
}
else
{ // Wuss hit when empty.
FX_AddQuad2( endpos, normal, random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200,
cgs.media.sunnyFlareShader );
}
}
// "Fun" sparks... Not when empty.
if ( spark && !empty)
{
sparks = rand() & 1 + 1;
for(;sparks>0;sparks--)
{
size = 0.2f + (random() * 0.4);
FXE_Spray( normal, 200, 75, 0.8f, velocity);
if (rand() & LEF_USE_COLLISION)
{ // This spark bounces.
FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f,
size, -size, 1.0f, 0.5f, 0.4f, 500.0f, cgs.media.sparkShader);
}
else
{
FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f,
size, -size, 1.0f, 0.5f, 0.0, 500.0f, cgs.media.sparkShader);
}
}
}
}