rpgxef/code/cgame/cg_effects.c
Walter Julius Hennecke a39565b783 Integrated RPG-X2 rpgxEF edition into the rpgxEF repo
... not quite content with where the project files lie but it is ok for
now.
... compiling works fine so far (only tested mingw32 right now)
2012-08-04 12:54:37 +02:00

609 lines
14 KiB
C

// Copyright (C) 1999-2000 Id Software, Inc.
//
// cg_effects.c -- these functions generate localentities, usually as a result
// of event processing
#include "cg_local.h"
#include "fx_local.h"
/*
==================
CG_BubbleTrail
Bullets shot underwater
==================
*/
void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
vec3_t move;
vec3_t vec;
float len;
int i;
VectorCopy (start, move);
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
// advance a random amount first
i = rand() % (int)spacing;
VectorMA( move, i, vec, move );
VectorScale (vec, spacing, vec);
for ( ; i < len; i += spacing ) {
localEntity_t *le;
refEntity_t *re;
le = CG_AllocLocalEntity();
le->leFlags = LEF_PUFF_DONT_SCALE;
le->leType = LE_MOVE_SCALE_FADE;
le->startTime = cg.time;
le->endTime = cg.time + 1000 + random() * 250;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
re = &le->refEntity;
//re->shaderTime = cg.time / 1000.0f;
re->shaderTime = cg.time * 0.001f;
re->reType = RT_SPRITE;
re->data.sprite.rotation = 0;
re->data.sprite.radius = 3;
re->customShader = cgs.media.waterBubbleShader;
re->shaderRGBA[0] = 0xff;
re->shaderRGBA[1] = 0xff;
re->shaderRGBA[2] = 0xff;
re->shaderRGBA[3] = 0xff;
le->color[3] = 1.0;
le->pos.trType = TR_LINEAR;
le->pos.trTime = cg.time;
VectorCopy( move, le->pos.trBase );
le->pos.trDelta[0] = crandom()*5;
le->pos.trDelta[1] = crandom()*5;
le->pos.trDelta[2] = crandom()*5 + 6;
VectorAdd (move, vec, move);
}
}
/*
=====================
CG_SmokePuff
Adds a smoke puff or blood trail localEntity.
=====================
*/
localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
float radius,
float r, float g, float b, float a,
float duration,
int startTime,
int leFlags,
qhandle_t hShader ) {
static int seed = 0x92;
localEntity_t *le;
refEntity_t *re;
le = CG_AllocLocalEntity();
le->leFlags = leFlags;
le->data.sprite.radius = radius;
re = &le->refEntity;
re->data.sprite.rotation = Q_random( &seed ) * 360;
re->data.sprite.radius = radius;
//re->shaderTime = startTime / 1000.0f;
re->shaderTime = startTime * 0.001f;
le->leType = LE_MOVE_SCALE_FADE;
le->startTime = startTime;
le->endTime = startTime + duration;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
le->color[0] = r;
le->color[1] = g;
le->color[2] = b;
le->color[3] = a;
le->pos.trType = TR_LINEAR;
le->pos.trTime = startTime;
VectorCopy( vel, le->pos.trDelta );
VectorCopy( p, le->pos.trBase );
VectorCopy( p, re->origin );
re->customShader = hShader;
// rage pro can't alpha fade, so use a different shader
if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
re->customShader = cgs.media.smokePuffRageProShader;
re->shaderRGBA[0] = 0xff;
re->shaderRGBA[1] = 0xff;
re->shaderRGBA[2] = 0xff;
re->shaderRGBA[3] = 0xff;
} else {
re->shaderRGBA[0] = le->color[0] * 0xff;
re->shaderRGBA[1] = le->color[1] * 0xff;
re->shaderRGBA[2] = le->color[2] * 0xff;
re->shaderRGBA[3] = 0xff;
}
re->reType = RT_SPRITE;
re->data.sprite.radius = le->data.sprite.radius;
return le;
}
/*
==================
CG_SpawnEffect
Player teleporting in or out
RPG-X: RedTechie Added refEntity_t *ent_legs, refEntity_t *ent_torso, refEntity_t *ent_head
==================
*/
void CG_SpawnEffect( vec3_t org, refEntity_t *ent_legs, refEntity_t *ent_torso, refEntity_t *ent_head ) {
localEntity_t *le;
refEntity_t *re;
FX_Transporter(org);
le = CG_AllocLocalEntity();
le->leFlags = 0;
le->leType = LE_FADE_RGB;
le->startTime = cg.time;
le->endTime = cg.time + 500;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
re = &le->refEntity;
//RPG-X: RedTechie - Added for better trans effect - dosnt work right now
//ent_legs->shaderTime = cg.time / 1000.0f;
//ent_head->shaderTime = cg.time / 1000.0f;
//ent_torso->shaderTime = cg.time / 1000.0f;
//ent_legs->customShader = cgs.media.teleportEffectShader;
//trap_R_AddRefEntityToScene( ent_legs );
//ent_head->customShader = cgs.media.teleportEffectShader;
//trap_R_AddRefEntityToScene( ent_head );
//ent_torso->customShader = cgs.media.teleportEffectShader;
//trap_R_AddRefEntityToScene( ent_torso );
//RPG-X: RedTechie - Playing with transporter crap
//re->shaderTime = cg.time / 1000.0f;
re->shaderTime = cg.time * 0.001f;
re = &le->refEntity;
re->reType = RT_MODEL;
//re->shaderTime = cg.time / 1000.0f;
re->shaderTime = cg.time * 0.001f;
re->customShader = cgs.media.teleportEffectShader;
re->hModel = cgs.media.teleportEffectModel;
AxisClear( re->axis );
VectorCopy( org, re->origin );
re->origin[2] -= 24;
}
void CG_QFlashEvent( vec3_t org ) {
localEntity_t *le;
/*refEntity_t *re;
le = CG_AllocLocalEntity();
le->leFlags = LEF_SINE_SCALE;
le->leType = LE_PARTICLE;
le->startTime = cg.time;
le->endTime = cg.time + 600;
le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0f;
le->data.particle.radius = 30;
le->data.particle.dradius = 5;
re = &le->refEntity;
re->customShader = cgs.media.qFlashSprite;
VectorCopy( org, re->origin );
VectorCopy( org, re->oldorigin );*/
le = FX_AddParticle( org, vec3_origin, qfalse, 110.0f, 109.0f,
1.0f, 1.0f, 0, 0,
290, cgs.media.qFlashSprite, 0 );
le->leFlags = LEF_SINE_SCALE | LEF_REVERSE_SCALE;
le->refEntity.renderfx |= RF_DEPTHHACK;
}
/*
====================
CG_MakeExplosion
====================
*/
localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
qhandle_t hModel, qhandle_t shader,
int msec, float scale, qboolean isSprite ) {
float ang;
localEntity_t *ex;
int offset;
vec3_t tmpVec, newOrigin;
if ( msec <= 0 ) {
CG_Error( "CG_MakeExplosion: msec = %i", msec );
}
// skew the time a bit so they aren't all in sync
offset = rand() & 63;
ex = CG_AllocLocalEntity();
if ( isSprite ) {
ex->leType = LE_SPRITE_EXPLOSION;
// randomly rotate sprite orientation
ex->refEntity.data.sprite.rotation = rand() % 360;
VectorScale( dir, 16, tmpVec );
VectorAdd( tmpVec, origin, newOrigin );
} else {
ex->leType = LE_EXPLOSION;
VectorCopy( origin, newOrigin );
// set axis with random rotate
if ( !dir ) {
AxisClear( ex->refEntity.axis );
} else {
ang = rand() % 360;
VectorCopy( dir, ex->refEntity.axis[0] );
RotateAroundDirection( ex->refEntity.axis, ang );
}
}
ex->startTime = cg.time - offset;
ex->endTime = ex->startTime + msec;
// bias the time so all shader effects start correctly
//ex->refEntity.shaderTime = ex->startTime / 1000.0f;
ex->refEntity.shaderTime = ex->startTime * 0.001f;
ex->refEntity.hModel = hModel;
ex->refEntity.customShader = shader;
// set origin
VectorCopy( newOrigin, ex->refEntity.origin );
VectorCopy( newOrigin, ex->refEntity.oldorigin );
//Scale the explosion
if (scale != 1) {
ex->refEntity.nonNormalizedAxes = qtrue;
VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] );
VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] );
VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] );
}
ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
return ex;
}
localEntity_t *CG_MakeExplosion2( vec3_t origin, vec3_t dir,
qhandle_t hModel, int numFrames, qhandle_t shader,
int msec, qboolean isSprite, float scale, int flags) {
float ang;
localEntity_t *ex;
int offset;
vec3_t tmpVec, newOrigin;
if ( msec <= 0 ) {
CG_Error( "CG_MakeExplosion: msec = %i", msec );
}
// skew the time a bit so they aren't all in sync
offset = rand() & 63;
ex = CG_AllocLocalEntity();
if ( isSprite ) {
ex->leType = LE_SPRITE_EXPLOSION;
// randomly rotate sprite orientation
ex->refEntity.data.sprite.rotation = rand() % 360;
VectorScale( dir, 16, tmpVec );
VectorAdd( tmpVec, origin, newOrigin );
} else {
ex->leType = LE_EXPLOSION;
VectorCopy( origin, newOrigin );
// set axis with random rotate
if ( !dir ) {
AxisClear( ex->refEntity.axis );
} else {
ang = rand() % 360;
VectorCopy( dir, ex->refEntity.axis[0] );
RotateAroundDirection( ex->refEntity.axis, ang );
}
}
ex->startTime = cg.time - offset;
ex->endTime = ex->startTime + msec;
// bias the time so all shader effects start correctly
//ex->refEntity.shaderTime = ex->startTime / 1000.0f;
ex->refEntity.shaderTime = ex->startTime * 0.001f;
ex->refEntity.hModel = hModel;
ex->refEntity.customShader = shader;
ex->lifeRate = (float)numFrames / msec;
ex->leFlags = flags;
//Scale the explosion
if (scale != 1) {
ex->refEntity.nonNormalizedAxes = qtrue;
VectorScale( ex->refEntity.axis[0], scale, ex->refEntity.axis[0] );
VectorScale( ex->refEntity.axis[1], scale, ex->refEntity.axis[1] );
VectorScale( ex->refEntity.axis[2], scale, ex->refEntity.axis[2] );
}
// set origin
VectorCopy( newOrigin, ex->refEntity.origin );
VectorCopy( newOrigin, ex->refEntity.oldorigin );
ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
return ex;
}
/*
=================
CG_Bleed
This is the spurt of blood when a character gets hit
=================
*/
/*void CG_Bleed( vec3_t origin, int entityNum ) {
localEntity_t *ex;
if ( !cg_blood.integer ) {
return;
}
ex = CG_AllocLocalEntity();
ex->leType = LE_EXPLOSION;
ex->startTime = cg.time;
ex->endTime = ex->startTime + 500;
VectorCopy ( origin, ex->refEntity.origin);
ex->refEntity.reType = RT_SPRITE;
ex->refEntity.data.sprite.rotation = rand() % 360;
ex->refEntity.data.sprite.radius = 16;
ex->refEntity.customShader = cgs.media.bloodExplosionShader;
// don't show player's own blood in view
if ( entityNum == cg.snap->ps.clientNum ) {
ex->refEntity.renderfx |= RF_THIRD_PERSON;
}
}*/
/*
-------------------------
CG_ExplosionEffects
Used to find the player and shake the camera if close enough
intensity ranges from 1 (minor tremble) to 16 (major quake)
-------------------------
*/
void CG_ExplosionEffects( vec3_t origin, int intensity, int radius)
{
//FIXME: When exactly is the vieworg calculated in relation to the rest of the frame?s
vec3_t dir;
float dist, intensityScale;
float realIntensity;
VectorSubtract( cg.refdef.vieworg, origin, dir );
dist = VectorNormalize( dir );
//Use the dir to add kick to the explosion
if ( dist > radius )
return;
intensityScale = 1 - ( dist / (float) radius );
realIntensity = intensity * intensityScale;
CG_CameraShake( realIntensity, 500, qfalse );
}
/*
=================
CG_Seeker
=================
*/
/*void CG_Seeker( centity_t *cent )
{
refEntity_t re;
vec3_t seekerOrg, viewAng;
float angle;
angle = cg.time/100.0f;
seekerOrg[0] = cent->lerpOrigin[0] + 18 * cos(angle);
seekerOrg[1] = cent->lerpOrigin[1] + 18 * sin(angle);
seekerOrg[2] = cent->lerpOrigin[2] + cg.predictedPlayerState.viewheight + 8 + (3*cos(cg.time/150.0f));
memset( &re, 0, sizeof( re ) );
re.reType = RT_MODEL;
VectorCopy ( seekerOrg, re.origin);
re.hModel = cgs.media.seekerModel;
re.shaderTime = (cg.time / 1000.0f);
VectorCopy (cent->lerpAngles , viewAng); // so the seeker faces the same direction the player is
viewAng[0] = -90; // but, we don't want the seeker facing up or down, always horizontal
AnglesToAxis( viewAng, re.axis );
VectorScale(re.axis[0], 0.5, re.axis[0]);
VectorScale(re.axis[1], 0.5, re.axis[1]);
VectorScale(re.axis[2], 0.5, re.axis[2]);
re.nonNormalizedAxes=qtrue;
trap_R_AddRefEntityToScene( &re );
}*/
/*
-------------------------
CG_Smoke
TiM: Ported from EF SP
-------------------------
*/
//void CG_Smoke( vec3_t origin, vec3_t dir, float radius, float speed, qhandle_t shader )
//{
// vec3_t velocity/*, accel*/;
// int i;
// for ( i = 0; i < 3; i++ )
// {
// velocity[i] = dir[i] + ( 0.2f * crandom());
// }
// VectorScale( velocity, speed, velocity );
//VectorScale( velocity, -0.25f, accel );
//accel[2] = random() * 12.0f + 6.0f;
// FX_AddSprite( origin,
// velocity,
// qfalse, //accel
// radius + (crandom() * radius * 0.5f ),
// radius + (crandom() * radius),
// 0.9f + crandom(),
// 0.0f,
// 16.0f + random() * 45.0f,
// 0.5f,
// 2000,
// shader ); //flags
//}
qboolean SmokeThink( localEntity_t *le )
{
vec3_t velocity/*, accel*/;
vec3_t origin;
vec3_t dir;
float speed;
int i;
VectorCopy( le->data.spawner.dir, dir );
//clamp the smoke vector
//Smoke should always go up
dir[2] = Com_Clamp( 0.85f, 1.0f, dir[2] );
for ( i = 0; i < 3; i++ )
{
velocity[i] = dir[i] + ( 0.2f * crandom());
}
VectorMA( le->refEntity.origin, 1, le->data.spawner.dir, origin);
//slow down the smoke the smaller it gets
//else it scatters too much
speed = le->data.spawner.data1 * 2.4;
VectorScale( velocity, speed, velocity ); //speed
//VectorScale( velocity, -0.25f, accel );
//accel[2] = random() * 12.0f + 6.0f;
FX_AddSprite( origin,
velocity,
qfalse, //accel
le->data.spawner.data1 + (crandom() * le->data.spawner.data1 * 0.5f ),
le->data.spawner.data1 + (crandom() * le->data.spawner.data1),
0.8 /*+ crandom()*/,
0.0,
16.0f + random() * 45.0f,
0.5f,
7000,
cgs.media.smokeShader ); //flags
return qtrue;
}
/*
======================
CG_Smoke
Creates a smoke effect
======================
*/
void CG_Smoke( vec3_t position, vec3_t dir, int killTime, int radius )
{
//CG_Printf( " %f %f %f\n", dir[0], dir[1], dir[2] );
// give it a lifetime of 10 seconds because the refresh thinktime in g_fx.c is 10 seconds
FX_AddSpawner( position, dir, NULL, NULL, qfalse, 0, 0.15, killTime, SmokeThink, radius ); //
}
/*
======================
FireThink
Engage fire effect
RPG-X | Marcin | 24/12/2008
======================
*/
qboolean FireThink( localEntity_t *le )
{
vec3_t direction;
vec3_t origin;
VectorCopy( le->data.spawner.dir, direction );
VectorMA( le->refEntity.origin, 1, direction, origin );
origin[2] += 60.0f / (80.0f / le->data.spawner.data1); // extra offset
FX_AddSprite( origin,
0,
qfalse,
le->data.spawner.data1,
0,
1.0f,
0.0f,
0,
0.5f,
600,
cgs.media.fireShader );
return qtrue;
}
/*
======================
CG_Fire
Creates a fire effect
RPG-X | Marcin | 24/12/2008
======================
*/
void CG_Fire( vec3_t position, vec3_t direction, int killTime, int radius, int fxEnt )
{
if(fxEnt)
FX_AddSpawner( position, direction, NULL, NULL, qfalse, 500, 0, killTime + 1000, FireThink, radius );
else
FX_AddSpawner( position, direction, NULL, NULL, qfalse, 500, 0, killTime, FireThink, radius );
}
//localEntity_t *FX_AddSprite(vec3_t origin, vec3_t velocity, qboolean gravity, float scale, float dscale,
// float startalpha, float endalpha, float roll, float elasticity,
// float killTime, qhandle_t shader)