mirror of
https://github.com/blendogames/gravitybone.git
synced 2025-01-30 23:40:39 +00:00
3902 lines
83 KiB
C
3902 lines
83 KiB
C
/*
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// cl_fx.c -- particle effects parsing and management
|
|
|
|
#include "client.h"
|
|
#include "particles.h"
|
|
|
|
void CL_LogoutEffect (vec3_t org, int type);
|
|
void CL_ItemRespawnParticles (vec3_t org);
|
|
void thinkDecalAlpha (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time);
|
|
void vectoanglerolled (vec3_t value1, float angleyaw, vec3_t angles);
|
|
|
|
//Knightmare- Psychospaz's smoke
|
|
void CL_GunSmokeEffect (vec3_t org, vec3_t dir);
|
|
|
|
static vec3_t avelocities [NUMVERTEXNORMALS];
|
|
|
|
extern struct model_s *cl_mod_smoke;
|
|
extern struct model_s *cl_mod_flash;
|
|
|
|
//here i convert old 256 color to RGB
|
|
const byte default_pal[768] =
|
|
{
|
|
0,0,0,15,15,15,31,31,31,47,47,47,63,63,63,75,75,75,91,91,91,107,107,107,123,123,123,139,139,139,155,155,155,171,171,171,187,187,187,203,203,203,219,219,219,235,235,235,99,75,35,91,67,31,83,63,31,79,59,27,71,55,27,63,47,
|
|
23,59,43,23,51,39,19,47,35,19,43,31,19,39,27,15,35,23,15,27,19,11,23,15,11,19,15,7,15,11,7,95,95,111,91,91,103,91,83,95,87,79,91,83,75,83,79,71,75,71,63,67,63,59,59,59,55,55,51,47,47,47,43,43,39,
|
|
39,39,35,35,35,27,27,27,23,23,23,19,19,19,143,119,83,123,99,67,115,91,59,103,79,47,207,151,75,167,123,59,139,103,47,111,83,39,235,159,39,203,139,35,175,119,31,147,99,27,119,79,23,91,59,15,63,39,11,35,23,7,167,59,43,
|
|
159,47,35,151,43,27,139,39,19,127,31,15,115,23,11,103,23,7,87,19,0,75,15,0,67,15,0,59,15,0,51,11,0,43,11,0,35,11,0,27,7,0,19,7,0,123,95,75,115,87,67,107,83,63,103,79,59,95,71,55,87,67,51,83,63,
|
|
47,75,55,43,67,51,39,63,47,35,55,39,27,47,35,23,39,27,19,31,23,15,23,15,11,15,11,7,111,59,23,95,55,23,83,47,23,67,43,23,55,35,19,39,27,15,27,19,11,15,11,7,179,91,79,191,123,111,203,155,147,215,187,183,203,
|
|
215,223,179,199,211,159,183,195,135,167,183,115,151,167,91,135,155,71,119,139,47,103,127,23,83,111,19,75,103,15,67,91,11,63,83,7,55,75,7,47,63,7,39,51,0,31,43,0,23,31,0,15,19,0,7,11,0,0,0,139,87,87,131,79,79,
|
|
123,71,71,115,67,67,107,59,59,99,51,51,91,47,47,87,43,43,75,35,35,63,31,31,51,27,27,43,19,19,31,15,15,19,11,11,11,7,7,0,0,0,151,159,123,143,151,115,135,139,107,127,131,99,119,123,95,115,115,87,107,107,79,99,99,
|
|
71,91,91,67,79,79,59,67,67,51,55,55,43,47,47,35,35,35,27,23,23,19,15,15,11,159,75,63,147,67,55,139,59,47,127,55,39,119,47,35,107,43,27,99,35,23,87,31,19,79,27,15,67,23,11,55,19,11,43,15,7,31,11,7,23,
|
|
7,0,11,0,0,0,0,0,119,123,207,111,115,195,103,107,183,99,99,167,91,91,155,83,87,143,75,79,127,71,71,115,63,63,103,55,55,87,47,47,75,39,39,63,35,31,47,27,23,35,19,15,23,11,7,7,155,171,123,143,159,111,135,151,99,
|
|
123,139,87,115,131,75,103,119,67,95,111,59,87,103,51,75,91,39,63,79,27,55,67,19,47,59,11,35,47,7,27,35,0,19,23,0,11,15,0,0,255,0,35,231,15,63,211,27,83,187,39,95,167,47,95,143,51,95,123,51,255,255,255,255,255,
|
|
211,255,255,167,255,255,127,255,255,83,255,255,39,255,235,31,255,215,23,255,191,15,255,171,7,255,147,0,239,127,0,227,107,0,211,87,0,199,71,0,183,59,0,171,43,0,155,31,0,143,23,0,127,15,0,115,7,0,95,0,0,71,0,0,47,
|
|
0,0,27,0,0,239,0,0,55,55,255,255,0,0,0,0,255,43,43,35,27,27,23,19,19,15,235,151,127,195,115,83,159,87,51,123,63,27,235,211,199,199,171,155,167,139,119,135,107,87,159,91,83
|
|
};
|
|
|
|
//this initializes all particle images - mods play with this...
|
|
void SetParticleImages (void)
|
|
{
|
|
R_SetParticlePicture(particle_generic, "gfx/particles/basic.tga");
|
|
R_SetParticlePicture(particle_freongeneric, "gfx/particles/freonbasic.tga");
|
|
R_SetParticlePicture(particle_smoke, "gfx/particles/smoke.tga");
|
|
R_SetParticlePicture(particle_blood, "gfx/particles/blood.tga");
|
|
R_SetParticlePicture(particle_blooddrop, "gfx/particles/blood_drop.tga");
|
|
R_SetParticlePicture(particle_blooddrip, "gfx/particles/blood_drip.tga");
|
|
R_SetParticlePicture(particle_redblood, "gfx/particles/blood_red.tga");
|
|
R_SetParticlePicture(particle_bubble, "gfx/particles/bubble.tga");
|
|
R_SetParticlePicture(particle_blaster, "gfx/particles/blaster.tga");
|
|
R_SetParticlePicture(particle_beam, "gfx/particles/beam.tga");
|
|
R_SetParticlePicture(particle_beam2, "gfx/particles/beam2.tga"); // only used for railgun
|
|
R_SetParticlePicture(particle_lightning, "gfx/particles/lightning.tga");
|
|
R_SetParticlePicture(particle_lensflare, "gfx/particles/lensflare.tga");
|
|
R_SetParticlePicture(particle_lightflare, "gfx/particles/lightflare.jpg");
|
|
R_SetParticlePicture(particle_inferno, "gfx/particles/inferno.tga");
|
|
R_SetParticlePicture(particle_shield, "gfx/particles/shield.jpg");
|
|
//animations
|
|
//rocket explosion
|
|
R_SetParticlePicture(particle_rflash, "gfx/particles/r_flash.tga");
|
|
R_SetParticlePicture(particle_rexplosion1, "gfx/particles/r_explod_1.tga");
|
|
R_SetParticlePicture(particle_rexplosion2, "gfx/particles/r_explod_2.tga");
|
|
R_SetParticlePicture(particle_rexplosion3, "gfx/particles/r_explod_3.tga");
|
|
R_SetParticlePicture(particle_rexplosion4, "gfx/particles/r_explod_4.tga");
|
|
R_SetParticlePicture(particle_rexplosion5, "gfx/particles/r_explod_5.tga");
|
|
R_SetParticlePicture(particle_rexplosion6, "gfx/particles/r_explod_6.tga");
|
|
R_SetParticlePicture(particle_rexplosion7, "gfx/particles/r_explod_7.tga");
|
|
//disruptor explosion
|
|
R_SetParticlePicture(particle_dexplosion1, "gfx/particles/d_explod_1.tga");
|
|
R_SetParticlePicture(particle_dexplosion2, "gfx/particles/d_explod_2.tga");
|
|
R_SetParticlePicture(particle_dexplosion3, "gfx/particles/d_explod_3.tga");
|
|
|
|
R_SetParticlePicture(particle_bulletmark, "gfx/decals/bulletmark.tga");
|
|
R_SetParticlePicture(particle_shadow, "gfx/decals/shadow.tga");
|
|
R_SetParticlePicture(particle_burnmark, "gfx/decals/burnmark.tga");
|
|
R_SetParticlePicture(particle_blooddecal1, "gfx/decals/blood_1.tga");
|
|
R_SetParticlePicture(particle_blooddecal2, "gfx/decals/blood_2.tga");
|
|
R_SetParticlePicture(particle_blooddecal3, "gfx/decals/blood_3.tga");
|
|
R_SetParticlePicture(particle_blooddecal4, "gfx/decals/blood_4.tga");
|
|
R_SetParticlePicture(particle_blooddecal5, "gfx/decals/blood_5.tga");
|
|
R_SetParticlePicture(particle_footprint, "gfx/decals/footprint.tga");
|
|
R_SetParticlePicture(particle_glass, "gfx/particles/glass.tga");
|
|
R_SetParticlePicture(particle_glass2, "gfx/particles/glass2.tga");
|
|
}
|
|
|
|
int particleBlood(void)
|
|
{
|
|
return particle_blooddecal1 + rand()%5;
|
|
}
|
|
|
|
|
|
void pRotateThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time);
|
|
|
|
int color8red (int color8)
|
|
{
|
|
return (default_pal[color8*3+0]);
|
|
}
|
|
int color8green (int color8)
|
|
{
|
|
return (default_pal[color8*3+1]);;
|
|
}
|
|
int color8blue (int color8)
|
|
{
|
|
return (default_pal[color8*3+2]);;
|
|
}
|
|
|
|
/*
|
|
==============================================================
|
|
|
|
PARTICLE MANAGEMENT
|
|
|
|
==============================================================
|
|
*/
|
|
|
|
float newParticleTime ()
|
|
{
|
|
float lerpedTime;
|
|
|
|
lerpedTime = cl.time;
|
|
|
|
return lerpedTime;
|
|
}
|
|
|
|
|
|
cparticle_t *active_particles, *free_particles;
|
|
cparticle_t particles[MAX_PARTICLES];
|
|
int cl_numparticles = MAX_PARTICLES;
|
|
|
|
#ifdef DECALS
|
|
//=================================================
|
|
decalpolys_t *active_decals, *free_decals;
|
|
decalpolys_t decalfrags[MAX_DECAL_FRAGS];
|
|
int cl_numdecalfrags = MAX_DECAL_FRAGS;
|
|
|
|
/*
|
|
===============
|
|
CleanDecalPolys
|
|
Cleans up the active_particles linked list
|
|
===============
|
|
*/
|
|
void CleanDecalPolys (void)
|
|
{
|
|
decalpolys_t *d, *next;
|
|
decalpolys_t *active = NULL, *tail = NULL;
|
|
|
|
for (d=active_decals; d; d=next)
|
|
{
|
|
next = d->next;
|
|
if (d->clearflag) {
|
|
d->clearflag = false;
|
|
d->numpolys = 0;
|
|
d->nextpoly = NULL;
|
|
d->node = NULL; // vis node
|
|
d->next = free_decals;
|
|
free_decals = d;
|
|
continue;
|
|
}
|
|
d->next = NULL;
|
|
if (!tail)
|
|
active = tail = d;
|
|
else {
|
|
tail->next = d;
|
|
tail = d;
|
|
}
|
|
}
|
|
active_decals = active;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
ClearDecalPoly
|
|
Recursively flags a decal poly chain for cleaning
|
|
===============
|
|
*/
|
|
void ClearDecalPoly (decalpolys_t *decal)
|
|
{
|
|
if (!decal)
|
|
return;
|
|
if (decal->nextpoly)
|
|
ClearDecalPoly(decal->nextpoly);
|
|
decal->clearflag = true; // tell cleaning loop to clean this up
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_ClearAllDecalPolys
|
|
Clears all decal polys
|
|
===============
|
|
*/
|
|
void CL_ClearAllDecalPolys (void)
|
|
{
|
|
int i;
|
|
free_decals = &decalfrags[0];
|
|
active_decals = NULL;
|
|
|
|
for (i=0 ;i < cl_numdecalfrags ; i++) {
|
|
decalfrags[i].next = &decalfrags[i+1];
|
|
decalfrags[i].clearflag = false;
|
|
decalfrags[i].numpolys = 0;
|
|
decalfrags[i].nextpoly = NULL;
|
|
decalfrags[i].node = NULL; // vis node
|
|
}
|
|
decalfrags[cl_numdecalfrags-1].next = NULL;
|
|
}
|
|
/*
|
|
===============
|
|
NumFreeDecalPolys
|
|
Retuns number of available decalpoly_t fields
|
|
===============
|
|
*/
|
|
int NumFreeDecalPolys (void)
|
|
{
|
|
int count = 0;
|
|
decalpolys_t *d = NULL;
|
|
for (d = free_decals; d; d = d->next)
|
|
count++;
|
|
return count;
|
|
}
|
|
/*
|
|
===============
|
|
NewDecalPoly
|
|
Retuns first free decal poly
|
|
===============
|
|
*/
|
|
decalpolys_t *NewDecalPoly(void)
|
|
{
|
|
decalpolys_t *d = NULL;
|
|
if (!free_decals)
|
|
return NULL;
|
|
|
|
d = free_decals;
|
|
free_decals = d->next;
|
|
d->next = active_decals;
|
|
active_decals = d;
|
|
return d;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
clipDecal
|
|
===============
|
|
*/
|
|
void clipDecal (cparticle_t *part, float radius, float orient, vec3_t origin, vec3_t dir)
|
|
{
|
|
vec3_t axis[3], verts[MAX_DECAL_VERTS];
|
|
int numfragments, j, i;
|
|
markFragment_t *fr, fragments[MAX_FRAGMENTS_PER_DECAL];
|
|
|
|
// invalid decal
|
|
if ( radius <= 0 || VectorCompare (dir, vec3_origin) )
|
|
return;
|
|
|
|
// calculate orientation matrix
|
|
VectorNormalize2 ( dir, axis[0] );
|
|
PerpendicularVector ( axis[1], axis[0] );
|
|
RotatePointAroundVector ( axis[2], axis[0], axis[1], orient );
|
|
CrossProduct ( axis[0], axis[2], axis[1] );
|
|
|
|
numfragments = R_MarkFragments (origin, axis, radius, MAX_DECAL_VERTS, verts,
|
|
MAX_FRAGMENTS_PER_DECAL, fragments);
|
|
|
|
if (!numfragments)
|
|
return;
|
|
if (numfragments > NumFreeDecalPolys()) // not enough decalpolys free
|
|
return;
|
|
|
|
VectorScale ( axis[1], 0.5f / radius, axis[1] );
|
|
VectorScale ( axis[2], 0.5f / radius, axis[2] );
|
|
|
|
part->decalnum = numfragments;
|
|
for ( i = 0, fr = fragments; i < numfragments; i++, fr++ )
|
|
{
|
|
decalpolys_t *decal = NewDecalPoly();
|
|
vec3_t v;
|
|
|
|
if (!decal)
|
|
return;
|
|
decal->nextpoly = part->decal;
|
|
part->decal = decal;
|
|
//Com_Printf("Number of verts in fragment: %i\n", fr->numPoints);
|
|
decal->node = fr->node; // vis node
|
|
|
|
for ( j = 0; j < fr->numPoints && j < MAX_VERTS_PER_FRAGMENT; j++ )
|
|
{
|
|
VectorCopy ( verts[fr->firstPoint+j], decal->polys[j] );
|
|
VectorSubtract ( decal->polys[j], origin, v );
|
|
decal->coords[j][0] = DotProduct ( v, axis[1] ) + 0.5f;
|
|
decal->coords[j][1] = DotProduct ( v, axis[2] ) + 0.5f;
|
|
decal->numpolys = fr->numPoints;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
===============
|
|
setupParticle
|
|
===============
|
|
*/
|
|
cparticle_t *setupParticle (
|
|
float angle0, float angle1, float angle2,
|
|
float org0, float org1, float org2,
|
|
float vel0, float vel1, float vel2,
|
|
float accel0, float accel1, float accel2,
|
|
float color0, float color1, float color2,
|
|
float colorvel0, float colorvel1, float colorvel2,
|
|
float alpha, float alphavel,
|
|
int blendfunc_src, int blendfunc_dst,
|
|
float size, float sizevel,
|
|
int image,
|
|
int flags,
|
|
void (*think)(cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time),
|
|
qboolean thinknext)
|
|
{
|
|
int j;
|
|
cparticle_t *p = NULL;
|
|
|
|
if (!free_particles)
|
|
return NULL;
|
|
p = free_particles;
|
|
free_particles = p->next;
|
|
p->next = active_particles;
|
|
active_particles = p;
|
|
|
|
p->time = cl.time;
|
|
|
|
p->angle[0]=angle0;
|
|
p->angle[1]=angle1;
|
|
p->angle[2]=angle2;
|
|
|
|
p->org[0]=org0;
|
|
p->org[1]=org1;
|
|
p->org[2]=org2;
|
|
p->oldorg[0]=org0;
|
|
p->oldorg[1]=org1;
|
|
p->oldorg[2]=org2;
|
|
|
|
p->vel[0]=vel0;
|
|
p->vel[1]=vel1;
|
|
p->vel[2]=vel2;
|
|
|
|
p->accel[0]=accel0;
|
|
p->accel[1]=accel1;
|
|
p->accel[2]=accel2;
|
|
|
|
p->color[0]=color0;
|
|
p->color[1]=color1;
|
|
p->color[2]=color2;
|
|
|
|
p->colorvel[0]=colorvel0;
|
|
p->colorvel[1]=colorvel1;
|
|
p->colorvel[2]=colorvel2;
|
|
|
|
p->blendfunc_src = blendfunc_src;
|
|
p->blendfunc_dst = blendfunc_dst;
|
|
|
|
p->alpha=alpha;
|
|
p->alphavel=alphavel;
|
|
p->size=size;
|
|
p->sizevel=sizevel;
|
|
|
|
p->image=image;
|
|
p->flags=flags;
|
|
|
|
p->src_ent=0;
|
|
p->dst_ent=0;
|
|
|
|
if (think)
|
|
p->think = think;
|
|
else
|
|
p->think = NULL;
|
|
p->thinknext=thinknext;
|
|
|
|
for (j=0;j<P_LIGHTS_MAX;j++)
|
|
{
|
|
cplight_t *plight = &p->lights[j];
|
|
plight->isactive = false;
|
|
plight->light = 0;
|
|
plight->lightvel = 0;
|
|
plight->lightcol[0] = 0;
|
|
plight->lightcol[1] = 0;
|
|
plight->lightcol[2] = 0;
|
|
}
|
|
#ifdef DECALS
|
|
p->decalnum = 0;
|
|
p->decal = NULL;
|
|
|
|
if (flags & PART_DECAL)
|
|
{
|
|
vec3_t dir;
|
|
AngleVectors (p->angle, dir, NULL, NULL);
|
|
VectorNegate(dir, dir);
|
|
clipDecal(p, p->size, -p->angle[2], p->org, dir);
|
|
|
|
if (!p->decalnum) // kill on viewframe
|
|
p->alpha = 0;
|
|
}
|
|
#endif
|
|
return p;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
addParticleLight
|
|
===============
|
|
*/
|
|
void addParticleLight (cparticle_t *p,
|
|
float light, float lightvel,
|
|
float lcol0, float lcol1, float lcol2)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<P_LIGHTS_MAX; i++)
|
|
{
|
|
cplight_t *plight = &p->lights[i];
|
|
if (!plight->isactive)
|
|
{
|
|
plight->isactive = true;
|
|
plight->light = light;
|
|
plight->lightvel = lightvel;
|
|
plight->lightcol[0] = lcol0;
|
|
plight->lightcol[1] = lcol1;
|
|
plight->lightcol[2] = lcol2;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ClearParticles
|
|
===============
|
|
*/
|
|
void CL_ClearParticles (void)
|
|
{
|
|
int i;
|
|
|
|
free_particles = &particles[0];
|
|
active_particles = NULL;
|
|
|
|
for (i=0 ;i < cl_numparticles ; i++) {
|
|
particles[i].next = &particles[i+1];
|
|
#ifdef DECALS
|
|
particles[i].decalnum = 0; // Knightmare added
|
|
particles[i].decal = NULL; // Knightmare added
|
|
#endif
|
|
}
|
|
particles[cl_numparticles-1].next = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
GENERIC PARTICLE THINKING ROUTINES
|
|
===============
|
|
*/
|
|
//#define SplashSize 10
|
|
#define STOP_EPSILON 0.1
|
|
|
|
void calcPartVelocity(cparticle_t *p, float scale, float *time, vec3_t velocity)
|
|
{
|
|
float time1 = *time;
|
|
float time2 = time1*time1;
|
|
|
|
velocity[0] = scale * (p->vel[0]*time1 + (p->accel[0])*time2);
|
|
velocity[1] = scale * (p->vel[1]*time1 + (p->accel[1])*time2);
|
|
|
|
if (p->flags & PART_GRAVITY)
|
|
velocity[2] = scale * (p->vel[2]*time1 + (p->accel[2]-(PARTICLE_GRAVITY))*time2);
|
|
else
|
|
velocity[2] = scale * (p->vel[2]*time1 + (p->accel[2])*time2);
|
|
}
|
|
|
|
void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out)
|
|
{
|
|
float backoff, change;
|
|
int i;
|
|
|
|
backoff = VectorLength(in)*0.25 + DotProduct (in, normal) * 3.0f;
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
change = normal[i]*backoff;
|
|
out[i] = in[i] - change;
|
|
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
|
|
out[i] = 0;
|
|
}
|
|
}
|
|
|
|
void pBounceThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
float clipsize;
|
|
trace_t tr;
|
|
vec3_t velocity;
|
|
|
|
clipsize = *size*0.5;
|
|
if (clipsize<0.25) clipsize = 0.25;
|
|
tr = CL_BrushTrace (p->oldorg, org, clipsize, MASK_SOLID); // was 1
|
|
|
|
if (tr.fraction < 1)
|
|
{
|
|
calcPartVelocity(p, 1, time, velocity);
|
|
ClipVelocity(velocity, tr.plane.normal, p->vel);
|
|
|
|
VectorCopy(vec3_origin, p->accel);
|
|
VectorCopy(tr.endpos, p->org);
|
|
VectorCopy(p->org, org);
|
|
VectorCopy(p->org, p->oldorg);
|
|
|
|
p->alpha = *alpha;
|
|
p->size = *size;
|
|
|
|
p->start = p->time = newParticleTime();
|
|
|
|
if (p->flags&PART_GRAVITY && VectorLength(p->vel)<2)
|
|
p->flags &= ~PART_GRAVITY;
|
|
}
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_LightningBeam
|
|
===============
|
|
*/
|
|
/*void CL_LightningBeam(vec3_t start, vec3_t end, int srcEnt, int dstEnt, float size)
|
|
{
|
|
cparticle_t *list;
|
|
cparticle_t *p=NULL;
|
|
|
|
for (list=active_particles ; list ; list=list->next)
|
|
if (list->src_ent == srcEnt && list->dst_ent == dstEnt )
|
|
{
|
|
p=list;
|
|
p->time = cl.time;
|
|
VectorCopy(start, p->angle);
|
|
VectorCopy(end, p->org);
|
|
|
|
if (p->link)
|
|
{
|
|
p->link->time = cl.time;
|
|
VectorCopy(start, p->link->angle);
|
|
VectorCopy(end, p->link->org);
|
|
}
|
|
else
|
|
{
|
|
p->link = setupParticle (
|
|
start[0], start[1], start[2],
|
|
end[0], end[1], end[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
150, 150, 255,
|
|
0, 0, 0,
|
|
1, -1.0,
|
|
size, 0,
|
|
particle_beam,
|
|
PART_BEAM,
|
|
NULL,0);
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (p)
|
|
return;
|
|
|
|
p = setupParticle (
|
|
start[0], start[1], start[2],
|
|
end[0], end[1], end[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
115, 115, 255,
|
|
0, 0, 0,
|
|
1, -1.0,
|
|
size, 0,
|
|
particle_lightning,
|
|
PART_LIGHTNING,
|
|
NULL,0);
|
|
|
|
p->src_ent=srcEnt;
|
|
p->dst_ent=dstEnt;
|
|
|
|
p->link = setupParticle (
|
|
start[0], start[1], start[2],
|
|
end[0], end[1], end[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
150, 150, 255,
|
|
0, 0, 0,
|
|
1, -1.0,
|
|
size, 0,
|
|
particle_beam,
|
|
PART_BEAM,
|
|
NULL,0);
|
|
}*/
|
|
|
|
|
|
void CL_LightningBeam (vec3_t start, vec3_t end, int srcEnt, int dstEnt, float size)
|
|
{
|
|
cparticle_t *list;
|
|
cparticle_t *p=NULL;
|
|
|
|
for (list=active_particles ; list ; list=list->next)
|
|
if (list->src_ent == srcEnt && list->dst_ent == dstEnt && list->image == particle_lightning)
|
|
{
|
|
p=list;
|
|
/*p->start =*/ p->time = cl.time;
|
|
VectorCopy(start, p->angle);
|
|
VectorCopy(end, p->org);
|
|
|
|
return;
|
|
}
|
|
|
|
p = setupParticle (
|
|
start[0], start[1], start[2],
|
|
end[0], end[1], end[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -2,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size, 0,
|
|
particle_lightning,
|
|
PART_LIGHTNING,
|
|
0, false);
|
|
|
|
if (!p)
|
|
return;
|
|
|
|
p->src_ent=srcEnt;
|
|
p->dst_ent=dstEnt;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_Explosion_Decal
|
|
===============
|
|
*/
|
|
#ifdef DECALS
|
|
void CL_Explosion_Decal (vec3_t org, float size)
|
|
{
|
|
if (r_decals->value)
|
|
{
|
|
int i, j;
|
|
cparticle_t *p;
|
|
vec3_t angle[6], ang;
|
|
trace_t trace1, trace2;
|
|
vec3_t end1, end2, normal, sorg, dorg;
|
|
vec3_t planenormals[6];
|
|
|
|
VectorSet(angle[0], -1, 0, 0);
|
|
VectorSet(angle[1], 1, 0, 0);
|
|
VectorSet(angle[2], 0, 1, 0);
|
|
VectorSet(angle[3], 0, -1, 0);
|
|
VectorSet(angle[4], 0, 0, 1);
|
|
VectorSet(angle[5], 0, 0, -1);
|
|
|
|
for (i=0;i<6;i++)
|
|
{
|
|
VectorMA(org, -2, angle[i], sorg); // move origin 2 units back
|
|
VectorMA(sorg, size/2, angle[i], end1);
|
|
trace1 = CL_Trace (sorg, end1, 0, CONTENTS_SOLID);
|
|
if (trace1.fraction < 1) // hit a surface
|
|
{ // make sure we haven't hit this plane before
|
|
VectorCopy(trace1.plane.normal, planenormals[i]);
|
|
for (j=0; j<i; j++)
|
|
if (VectorCompare(planenormals[j],planenormals[i])) continue;
|
|
// try tracing directly to hit plane
|
|
VectorNegate(trace1.plane.normal, normal);
|
|
VectorMA(sorg, size/2, normal, end2);
|
|
trace2 = CL_Trace (sorg, end2, 0, CONTENTS_SOLID);
|
|
// if seond trace hit same plane
|
|
if (trace2.fraction < 1 && VectorCompare(trace2.plane.normal, trace1.plane.normal))
|
|
VectorCopy(trace2.endpos, dorg);
|
|
else
|
|
VectorCopy(trace1.endpos, dorg);
|
|
//if (CM_PointContents(dorg,0) & MASK_WATER) // no scorch marks underwater
|
|
// continue;
|
|
vectoanglerolled(normal, rand()%360, ang);
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
dorg[0],dorg[1],dorg[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_burnmark,
|
|
PART_SHADED|PART_DECAL|PART_ALPHACOLOR,
|
|
thinkDecalAlpha, true);
|
|
}
|
|
/*vectoanglerolled(angle[i], rand()%360, ang);
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
org[0], org[1], org[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -0.001,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_burnmark,
|
|
PART_SHADED|PART_DECAL|PART_ALPHACOLOR,
|
|
thinkDecalAlpha, true);*/
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_Explosion_Particle
|
|
|
|
Explosion effect
|
|
===============
|
|
*/
|
|
void pExplosionThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
if (*alpha>.85)
|
|
*image = particle_rexplosion1;
|
|
else if (*alpha>.7)
|
|
*image = particle_rexplosion2;
|
|
else if (*alpha>.5)
|
|
*image = particle_rexplosion3;
|
|
else if (*alpha>.4)
|
|
*image = particle_rexplosion4;
|
|
else if (*alpha>.25)
|
|
*image = particle_rexplosion5;
|
|
else if (*alpha>.1)
|
|
*image = particle_rexplosion6;
|
|
else
|
|
*image = particle_rexplosion7;
|
|
|
|
*alpha *= 3.0;
|
|
|
|
if (*alpha > 1.0)
|
|
*alpha = 1;
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void pExplosionBubbleThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
|
|
if (CM_PointContents(org,0) & MASK_WATER)
|
|
p->thinknext = true;
|
|
else
|
|
{
|
|
p->think = NULL;
|
|
p->alpha = 0;
|
|
}
|
|
}
|
|
|
|
void CL_Explosion_Particle (vec3_t org, float size, qboolean rocket)
|
|
{
|
|
cparticle_t *p;
|
|
|
|
p = setupParticle (
|
|
0, 0, 0,
|
|
org[0], org[1], org[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, (rocket)? -2 : -1.5,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
//GL_ONE, GL_ONE,
|
|
(size!=0)?size:(150-(!rocket)?75:0), 0,
|
|
particle_rexplosion1,
|
|
PART_DEPTHHACK_SHORT,
|
|
pExplosionThink, true);
|
|
|
|
if (p)
|
|
{ // smooth color blend :D
|
|
/* addParticleLight (p, 225, 0, 1, 0, 0);
|
|
addParticleLight (p, 250, 0, 1, 0.3, 0);
|
|
addParticleLight (p, 275, 0, 1, 0.6, 0);
|
|
addParticleLight (p, 300, 0, 1, 1, 0);*/
|
|
// use just one, 4 lights kills the framerate
|
|
addParticleLight (p, 300, 0, 1, 0.514, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_Explosion_FlashParticle
|
|
|
|
Explosion fash
|
|
===============
|
|
*/
|
|
void CL_Explosion_FlashParticle (vec3_t org, float size, qboolean large)
|
|
{
|
|
if (large)
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0], org[1], org[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 175, 100,
|
|
0, 0, 0,
|
|
1, -1.75,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
//GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
(size!=0)?size:50, -10,
|
|
//100-(!rocket)?50:0, -10,
|
|
particle_rflash,
|
|
PART_DEPTHHACK_SHORT,
|
|
NULL,0);
|
|
}
|
|
else
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0], org[1], org[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 175, 100,
|
|
0, 0, 0,
|
|
1, -1.75,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
(size!=0)?size:50, -10,
|
|
//100-(!rocket)?50:0, -10,
|
|
particle_blaster,
|
|
0,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_Explosion_Sparks
|
|
===============
|
|
*/
|
|
void pExplosionSparksThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
int i;
|
|
|
|
//setting up angle for sparks
|
|
{
|
|
float time1, time2;
|
|
|
|
time1 = *time;
|
|
time2 = time1*time1;
|
|
|
|
for (i=0;i<2;i++)
|
|
angle[i] = 0.25*(p->vel[i]*time1 + (p->accel[i])*time2);
|
|
angle[2] = 0.25*(p->vel[2]*time1 + (p->accel[2]-PARTICLE_GRAVITY)*time2);
|
|
}
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void CL_Explosion_Sparks (vec3_t org, int size)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < (64/cl_particle_scale->value); i++) // was 256
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] + ((rand()%size)-16), org[1] + ((rand()%size)-16), org[2] + ((rand()%size)-16),
|
|
(rand()%150)-75, (rand()%150)-75, (rand()%150)-75,
|
|
0, 0, 0,
|
|
255, 100, 25,
|
|
0, 0, 0,
|
|
1, -0.8 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
6, -9, // was 4, -6
|
|
particle_blaster,
|
|
PART_GRAVITY|PART_SPARK,
|
|
pExplosionSparksThink, true);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
|
|
Blood effects
|
|
|
|
===============
|
|
*/
|
|
void pBloodThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time);
|
|
void CL_BloodPuff (vec3_t org, vec3_t dir, int count);
|
|
|
|
#define MAXBLEEDSIZE 5
|
|
#define TIMEBLOODGROW 2.5f
|
|
#define BLOOD_DECAL_CHANCE 0.5F
|
|
|
|
void pBloodDecalThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{ // This REALLY slows things down
|
|
/*if (*time<TIMEBLOODGROW)
|
|
{
|
|
vec3_t dir;
|
|
|
|
*size *= sqrt(0.5 + 0.5*(*time/TIMEBLOODGROW));
|
|
|
|
AngleVectors (angle, dir, NULL, NULL);
|
|
VectorNegate(dir, dir);
|
|
clipDecal(p, *size, angle[2], org, dir);
|
|
}*/
|
|
|
|
//now calc alpha
|
|
thinkDecalAlpha (p, org, angle, alpha, size, image, time);
|
|
}
|
|
|
|
void pBloodDropThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
float length;
|
|
vec3_t len;
|
|
|
|
VectorSubtract(p->angle, org, len);
|
|
{
|
|
calcPartVelocity(p, 0.2, time, angle);
|
|
|
|
length = VectorNormalize(angle);
|
|
if (length>MAXBLEEDSIZE) length = MAXBLEEDSIZE;
|
|
VectorScale(angle, -length, angle);
|
|
}
|
|
|
|
//now to trace for impact...
|
|
pBloodThink (p, org, angle, alpha, size, image, time);
|
|
}
|
|
|
|
void pBloodPuffThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
angle[2] = angle[0] + *time*angle[1] + *time**time*angle[2];
|
|
|
|
//now to trace for impact...
|
|
pBloodThink (p, org, angle, alpha, size, image, time);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
pBloodThink
|
|
===============
|
|
*/
|
|
void pBloodThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
trace_t trace = CL_Trace (p->oldorg, org, 0, CONTENTS_SOLID); // was 0.1
|
|
qboolean became_decal = false;
|
|
|
|
if (trace.fraction < 1.0) // delete and stain...
|
|
{
|
|
#ifdef DECALS
|
|
if (r_decals->value && (p->flags & PART_LEAVEMARK)
|
|
&& !VectorCompare(trace.plane.normal, vec3_origin)
|
|
&& !(CM_PointContents(p->oldorg,0) & MASK_WATER)) // no blood splatters underwater...
|
|
{
|
|
vec3_t normal, dir;
|
|
int i;
|
|
qboolean greenblood = false;
|
|
qboolean timedout = false;
|
|
if (p->color[1] > 0 && p->color[2] > 0)
|
|
greenblood = true;
|
|
// time cutoff for gib trails
|
|
if (p->flags & PART_GRAVITY && !(p->flags & PART_DIRECTION))
|
|
{ // gekk gibs go flyin faster...
|
|
if ((greenblood) && (cl.time - p->time)*0.001 > 1.0F)
|
|
timedout = true;
|
|
if ((!greenblood) && (cl.time - p->time)*0.001 > 0.5F)
|
|
timedout = true;
|
|
}
|
|
|
|
if (!timedout)
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
VectorNegate(trace.plane.normal, normal);
|
|
vectoanglerolled(normal, rand()%360, p->angle);
|
|
|
|
VectorCopy(trace.endpos, p->org);
|
|
VectorClear(p->vel);
|
|
VectorClear(p->accel);
|
|
p->image = particleBlood();
|
|
p->blendfunc_src = GL_SRC_ALPHA; //GL_ZERO
|
|
p->blendfunc_dst = GL_ONE_MINUS_SRC_ALPHA; //GL_ONE_MINUS_SRC_COLOR
|
|
p->flags = PART_DECAL|PART_SHADED|PART_ALPHACOLOR;
|
|
p->alpha = *alpha;
|
|
p->alphavel = -1/r_decal_life->value;
|
|
if (greenblood)
|
|
p->color[1] = 210;
|
|
else
|
|
for (i=0; i<3; i++)
|
|
p->color[i] *= 0.5;
|
|
p->start = newParticleTime();
|
|
p->think = pBloodDecalThink;
|
|
p->thinknext = true;
|
|
p->size = MAXBLEEDSIZE*0.5*(random()*5.0+5);
|
|
//p->size = *size*(random()*5.0+5);
|
|
p->sizevel = 0;
|
|
|
|
p->decalnum = 0;
|
|
p->decal = NULL;
|
|
AngleVectors (p->angle, dir, NULL, NULL);
|
|
VectorNegate(dir, dir);
|
|
clipDecal(p, p->size, -p->angle[2], p->org, dir);
|
|
if (p->decalnum)
|
|
{
|
|
became_decal = true;
|
|
|
|
//bc splat sound
|
|
|
|
if (rand()%2 == 1)
|
|
S_StartSound (org, 0, CHAN_BODY, S_RegisterSound("misc/fhit3.wav"), frand()*0.6 + 0.4, ATTN_NORM, 0);
|
|
}
|
|
//else
|
|
// Com_Printf(S_COLOR_YELLOW"Blood decal not clipped!\n");
|
|
}
|
|
}
|
|
if (!became_decal)
|
|
#endif
|
|
{
|
|
*alpha = 0;
|
|
*size = 0;
|
|
p->alpha = 0;
|
|
}
|
|
}
|
|
VectorCopy(org, p->oldorg);
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BloodSmack
|
|
===============
|
|
*/
|
|
void CL_BloodSmack (vec3_t org, vec3_t dir)
|
|
{
|
|
cparticle_t *p;
|
|
|
|
p = setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
org[0], org[1], org[2],
|
|
dir[0], dir[1], dir[2],
|
|
0, 0, 0,
|
|
255, 0, 0,
|
|
0, 0, 0,
|
|
1.0, -1 / (0.5 + frand()*0.3), //was -0.75
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
10, 0,
|
|
particle_redblood,
|
|
PART_SHADED|PART_OVERBRIGHT,
|
|
pRotateThink,true);
|
|
|
|
CL_BloodPuff(org, dir, 1);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BloodBleed
|
|
===============
|
|
*/
|
|
void CL_BloodBleed (vec3_t org, vec3_t dir, int count)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t pos;
|
|
int i;
|
|
|
|
VectorScale(dir, 10, pos);
|
|
for (i=0; i<count; i++)
|
|
{
|
|
VectorSet(pos,
|
|
dir[0]+random()*(cl_blood->value-2)*0.01,
|
|
dir[1]+random()*(cl_blood->value-2)*0.01,
|
|
dir[2]+random()*(cl_blood->value-2)*0.01);
|
|
VectorScale(pos, 10 + (cl_blood->value-2)*0.0001*random(), pos);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
org[0] + ((rand()&7)-4) + dir[0], org[1] + ((rand()&7)-4) + dir[1], org[2] + ((rand()&7)-4) + dir[2],
|
|
pos[0]*(random()*3+5), pos[1]*(random()*3+5), pos[2]*(random()*3+5),
|
|
0, 0, 0,
|
|
255, 0, 0,
|
|
0, 0, 0,
|
|
0.7, -0.25 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
MAXBLEEDSIZE*0.5, 0,
|
|
particle_blooddrip,
|
|
PART_SHADED|PART_DIRECTION|PART_GRAVITY|PART_OVERBRIGHT,
|
|
pBloodDropThink,true);
|
|
|
|
if (i == 0 && random() < BLOOD_DECAL_CHANCE)
|
|
p->flags |= PART_LEAVEMARK;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_BloodPuff
|
|
===============
|
|
*/
|
|
void CL_BloodPuff (vec3_t org, vec3_t dir, int count)
|
|
{
|
|
cparticle_t *p;
|
|
int i;
|
|
float d;
|
|
|
|
for (i=0; i<count; i++)
|
|
{
|
|
d = rand()&31;
|
|
p = setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
org[0] + ((rand()&7)-4) + d*dir[0], org[1] + ((rand()&7)-4) + d*dir[1], org[2] + ((rand()&7)-4) + d*dir[2],
|
|
dir[0]*(crand()*3+5), dir[1]*(crand()*3+5), dir[2]*(crand()*3+5),
|
|
0, 0, -100,
|
|
255, 0, 0,
|
|
0, 0, 0,
|
|
1.0, -1.0,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
10, 0,
|
|
particle_blood,
|
|
PART_SHADED,
|
|
pBloodPuffThink,true);
|
|
|
|
if (i == 0 && random() < BLOOD_DECAL_CHANCE)
|
|
p->flags |= PART_LEAVEMARK;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_BloodHit
|
|
===============
|
|
*/
|
|
void CL_BloodHit (vec3_t org, vec3_t dir)
|
|
{
|
|
if (cl_blood->value < 1) // disable blood option
|
|
return;
|
|
if (cl_blood->value == 2) // splat
|
|
CL_BloodSmack(org, dir);
|
|
else if (cl_blood->value == 3) // bleed
|
|
CL_BloodBleed (org, dir, 6);
|
|
else if (cl_blood->value == 4) // gore
|
|
CL_BloodBleed (org, dir, 16);
|
|
else // 1 = puff
|
|
CL_BloodPuff(org, dir, 5);
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CL_GreenBloodHit
|
|
|
|
green blood spray
|
|
==================
|
|
*/
|
|
void CL_GreenBloodHit (vec3_t org, vec3_t dir)
|
|
{
|
|
cparticle_t *p;
|
|
int i;
|
|
float d;
|
|
|
|
if (cl_blood->value < 1) // disable blood option
|
|
return;
|
|
|
|
for (i=0;i<5;i++)
|
|
{
|
|
d = rand()&31;
|
|
p = setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
org[0] + ((rand()&7)-4) + d*dir[0], org[1] + ((rand()&7)-4) + d*dir[1], org[2] + ((rand()&7)-4) + d*dir[2],
|
|
dir[0]*(crand()*3+5), dir[1]*(crand()*3+5), dir[2]*(crand()*3+5),
|
|
0, 0, -100,
|
|
255, 180, 50,
|
|
0, 0, 0,
|
|
1, -1.0,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
10, 0,
|
|
particle_blood,
|
|
PART_SHADED|PART_OVERBRIGHT,
|
|
pBloodPuffThink,true);
|
|
|
|
if (i == 0 && random() < BLOOD_DECAL_CHANCE)
|
|
p->flags |= PART_LEAVEMARK;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleEffect
|
|
|
|
Wall impact puffs
|
|
===============
|
|
*/
|
|
void CL_ParticleEffect (vec3_t org, vec3_t dir, int color8, int count)
|
|
{
|
|
int i;
|
|
float d;
|
|
vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)};
|
|
|
|
for (i=0 ; i<count ; i++)
|
|
{
|
|
d = rand()&31;
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] + ((rand()&7)-4) + d*dir[0], org[1] + ((rand()&7)-4) + d*dir[1], org[2] + ((rand()&7)-4) + d*dir[2],
|
|
crand()*20, crand()*20, crand()*20,
|
|
0, 0, 0,
|
|
color[0], color[1], color[2],
|
|
0, 0, 0,
|
|
1.0, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleEffect2
|
|
===============
|
|
*/
|
|
|
|
#define colorAdd 25
|
|
void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color8, int count)
|
|
{
|
|
int i;
|
|
float d;
|
|
vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)};
|
|
|
|
for (i=0 ; i<count ; i++)
|
|
{
|
|
d = rand()&7;
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0]+((rand()&7)-4)+d*dir[0], org[1]+((rand()&7)-4)+d*dir[1], org[2]+((rand()&7)-4)+d*dir[2],
|
|
crand()*20, crand()*20, crand()*20,
|
|
0, 0, 0,
|
|
color[0] + colorAdd, color[1] + colorAdd, color[2] + colorAdd,
|
|
0, 0, 0,
|
|
1, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
// RAFAEL
|
|
/*
|
|
===============
|
|
CL_ParticleEffect3
|
|
===============
|
|
*/
|
|
|
|
void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color8, int count)
|
|
{
|
|
int i;
|
|
float d;
|
|
vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)};
|
|
|
|
for (i=0 ; i<count ; i++)
|
|
{
|
|
d = rand()&7;
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0]+((rand()&7)-4)+d*dir[0], org[1]+((rand()&7)-4)+d*dir[1], org[2]+((rand()&7)-4)+d*dir[2],
|
|
crand()*20, crand()*20, crand()*20,
|
|
0, 0, 0,
|
|
color[0] + colorAdd, color[1] + colorAdd, color[2] + colorAdd,
|
|
0, 0, 0,
|
|
1, -0.25 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
2, -0.25,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL, false);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleEffectSplash
|
|
|
|
Water Splashing
|
|
===============
|
|
*/
|
|
#define SplashSize 7.5
|
|
void pSplashThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
int i;
|
|
vec3_t len;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
// *size *= (float)(SplashSize/VectorLength(len)) * 0.5/((4-*size));
|
|
// if (*size > SplashSize)
|
|
// *size = SplashSize;
|
|
|
|
//setting up angle for sparks
|
|
{
|
|
float time1, time2;
|
|
|
|
time1 = *time;
|
|
time2 = time1*time1;
|
|
|
|
for (i=0;i<2;i++)
|
|
angle[i] = 0.5*(p->vel[i]*time1 + (p->accel[i])*time2);
|
|
angle[2] = 0.5*(p->vel[2]*time1 + (p->accel[2]-PARTICLE_GRAVITY)*time2);
|
|
}
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void CL_ParticleEffectSplash (vec3_t org, vec3_t dir, int color8, int count)
|
|
{
|
|
int i;
|
|
float d;
|
|
vec3_t color = {color8red(color8), color8green(color8), color8blue(color8)};
|
|
|
|
for (i=0 ; i<count ; i++)
|
|
{
|
|
d = rand()&5;
|
|
setupParticle (
|
|
org[0], org[1], org[2],
|
|
org[0]+d*dir[0], org[1]+d*dir[1], org[2]+d*dir[2],
|
|
dir[0]*40 + crand()*10, dir[1]*40 + crand()*10, dir[2]*40 + crand()*10,
|
|
0, 0, 0,
|
|
color[0], color[1], color[2],
|
|
0, 0, 0,
|
|
1, -0.75 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
5, -7,
|
|
particle_smoke,
|
|
PART_GRAVITY|PART_DIRECTION /*|PART_TRANS|PART_SHADED*/,
|
|
pSplashThink,true);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleEffectSparks
|
|
===============
|
|
*/
|
|
void pSparksThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
//vec3_t dir;
|
|
int i;
|
|
|
|
//setting up angle for sparks
|
|
{
|
|
float time1, time2;
|
|
|
|
time1 = *time;
|
|
time2 = time1*time1;
|
|
|
|
for (i=0;i<2;i++)
|
|
angle[i] = 0.25*(p->vel[i]*time1 + (p->accel[i])*time2);
|
|
angle[2] = 0.25*(p->vel[2]*time1 + (p->accel[2]-PARTICLE_GRAVITY)*time2);
|
|
}
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void CL_ParticleEffectSparks (vec3_t org, vec3_t dir, vec3_t color, int count)
|
|
{
|
|
int i;
|
|
float d;
|
|
cparticle_t *p;
|
|
|
|
for (i=0 ; i<count ; i++)
|
|
{
|
|
d = rand()&7;
|
|
p = setupParticle (
|
|
0, 0, 0,
|
|
org[0]+((rand()&3)-2), org[1]+((rand()&3)-2), org[2]+((rand()&3)-2),
|
|
crand()*20 + dir[0]*40, crand()*20 + dir[1]*40, crand()*20 + dir[2]*40,
|
|
0, 0, 0,
|
|
color[0], color[1], color[2],
|
|
0, 0, 0,
|
|
0.75, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
4, 0, //Knightmare- increase size
|
|
particle_generic,
|
|
PART_GRAVITY|PART_SPARK,
|
|
pSparksThink,true);
|
|
}
|
|
if (p) // added light effect
|
|
addParticleLight (p, (count>8)?130:65, 0, color[0]/255, color[1]/255, color[2]/255);
|
|
}
|
|
|
|
|
|
#ifdef DECALS
|
|
/*
|
|
===============
|
|
thinkDecalAlpha
|
|
===============
|
|
*/
|
|
void thinkDecalAlpha (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
*alpha = pow(*alpha, 0.1);
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void vectoanglerolled (vec3_t value1, float angleyaw, vec3_t angles)
|
|
{
|
|
float forward, yaw, pitch;
|
|
|
|
yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
|
|
forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
|
|
pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
|
|
|
|
if (pitch < 0)
|
|
pitch += 360;
|
|
|
|
angles[PITCH] = -pitch;
|
|
angles[YAW] = yaw;
|
|
angles[ROLL] = - angleyaw;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleBulletDecal
|
|
===============
|
|
*/
|
|
#define DECAL_OFFSET 0.5f
|
|
void CL_ParticleBulletDecal (vec3_t org, vec3_t dir, float size)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t ang, angle, end, origin;
|
|
trace_t tr;
|
|
|
|
if (!r_decals->value)
|
|
return;
|
|
|
|
VectorMA(org, DECAL_OFFSET, dir, origin);
|
|
VectorMA(org, -DECAL_OFFSET, dir, end);
|
|
tr = CL_Trace (origin, end, 0, CONTENTS_SOLID);
|
|
//tr = CL_Trace (origin, end, 1, 1);
|
|
|
|
if (tr.fraction == 1)
|
|
//if (!tr.allsolid)
|
|
return;
|
|
|
|
VectorNegate(tr.plane.normal, angle);
|
|
//VectorNegate(dir, angle);
|
|
vectoanglerolled(angle, rand()%360, ang);
|
|
VectorCopy(tr.endpos, origin);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_bulletmark,
|
|
PART_SHADED|PART_DECAL|PART_ALPHACOLOR, // was part_saturate
|
|
thinkDecalAlpha, true);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleRailDecal
|
|
===============
|
|
*/
|
|
#define RAIL_DECAL_OFFSET 2.0f
|
|
void CL_ParticleRailDecal (vec3_t org, vec3_t dir, float size, qboolean isRed)
|
|
{
|
|
vec3_t ang, angle, end, origin;
|
|
trace_t tr;
|
|
|
|
if (!r_decals->value)
|
|
return;
|
|
|
|
VectorMA(org, -RAIL_DECAL_OFFSET, dir, origin);
|
|
VectorMA(org, 2*RAIL_DECAL_OFFSET, dir, end);
|
|
tr = CL_Trace (origin, end, 0, CONTENTS_SOLID);
|
|
|
|
if (tr.fraction==1)
|
|
return;
|
|
if (VectorCompare(tr.plane.normal, vec3_origin))
|
|
return;
|
|
|
|
VectorNegate(tr.plane.normal, angle);
|
|
vectoanglerolled(angle, rand()%360, ang);
|
|
VectorCopy(tr.endpos, origin);
|
|
|
|
setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_bulletmark,
|
|
PART_SHADED|PART_DECAL|PART_ALPHACOLOR,
|
|
thinkDecalAlpha, true);
|
|
|
|
setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
(isRed)?255:cl_railred->value, (isRed)?20:cl_railgreen->value, (isRed)?20:cl_railblue->value,
|
|
0, 0, 0,
|
|
1, -0.25,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size, 0,
|
|
particle_generic,
|
|
PART_DECAL,
|
|
NULL, false);
|
|
|
|
setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
1, -0.25,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size*0.67, 0,
|
|
particle_generic,
|
|
PART_DECAL,
|
|
NULL, false);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ParticleBlasterDecal
|
|
===============
|
|
*/
|
|
void CL_ParticleBlasterDecal (vec3_t org, vec3_t dir, float size, int red, int green, int blue)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t ang, angle, end, origin;
|
|
trace_t tr;
|
|
|
|
if (!r_decals->value)
|
|
return;
|
|
|
|
VectorMA(org, DECAL_OFFSET, dir, origin);
|
|
VectorMA(org, -DECAL_OFFSET, dir, end);
|
|
tr = CL_Trace (origin, end, 0, CONTENTS_SOLID);
|
|
|
|
if (tr.fraction==1)
|
|
return;
|
|
if (VectorCompare(tr.plane.normal, vec3_origin))
|
|
return;
|
|
|
|
VectorNegate(tr.plane.normal, angle);
|
|
vectoanglerolled(angle, rand()%360, ang);
|
|
VectorCopy(tr.endpos, origin);
|
|
/*
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.7, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_shadow,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);*/
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.5, -0.1,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size*0.4, 0,
|
|
particle_freongeneric,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.5, -0.3,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size*0.3, 0,
|
|
particle_freongeneric,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
}
|
|
|
|
|
|
|
|
void CL_ParticleFreonDecal (vec3_t org, vec3_t dir, float size, int red, int green, int blue)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t ang, angle, end, origin;
|
|
trace_t tr;
|
|
|
|
if (!r_decals->value)
|
|
return;
|
|
|
|
VectorMA(org, DECAL_OFFSET, dir, origin);
|
|
VectorMA(org, -DECAL_OFFSET, dir, end);
|
|
tr = CL_Trace (origin, end, 0, CONTENTS_SOLID);
|
|
|
|
if (tr.fraction==1)
|
|
return;
|
|
if (VectorCompare(tr.plane.normal, vec3_origin))
|
|
return;
|
|
|
|
VectorNegate(tr.plane.normal, angle);
|
|
vectoanglerolled(angle, rand()%360, ang);
|
|
VectorCopy(tr.endpos, origin);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.7, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_shadow,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
1, -0.3,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size*0.4, 0,
|
|
particle_generic,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
1, -0.6,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size*0.3, 0,
|
|
particle_generic,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ParticlePlasmaBeamDecal
|
|
===============
|
|
*/
|
|
void CL_ParticlePlasmaBeamDecal (vec3_t org, vec3_t dir, float size)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t ang, angle, end, origin;
|
|
trace_t tr;
|
|
|
|
if (!r_decals->value)
|
|
return;
|
|
|
|
VectorMA(org, DECAL_OFFSET, dir, origin);
|
|
VectorMA(org, -DECAL_OFFSET, dir, end);
|
|
tr = CL_Trace (origin, end, 0, CONTENTS_SOLID);
|
|
|
|
if (tr.fraction==1)
|
|
return;
|
|
if (VectorCompare(tr.plane.normal, vec3_origin))
|
|
return;
|
|
|
|
VectorNegate(tr.plane.normal, angle);
|
|
vectoanglerolled(angle, rand()%360, ang);
|
|
VectorCopy(tr.endpos, origin);
|
|
|
|
p = setupParticle (
|
|
ang[0], ang[1], ang[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.85, -1/r_decal_life->value,
|
|
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 0,
|
|
particle_shadow,
|
|
PART_SHADED|PART_DECAL,
|
|
NULL, false);
|
|
}
|
|
#endif // DECALS
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_TeleporterParticles
|
|
===============
|
|
*/
|
|
void CL_TeleporterParticles (entity_state_t *ent)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
ent->origin[0]-16+(rand()&31), ent->origin[1]-16+(rand()&31), ent->origin[2]-16+(rand()&31),
|
|
crand()*14, crand()*14, 80 + (rand()&7),
|
|
0, 0, 0,
|
|
230+crand()*25, 125+crand()*25, 25+crand()*25,
|
|
0, 0, 0,
|
|
1, -0.5,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
2, 0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_LogoutEffect
|
|
|
|
===============
|
|
*/
|
|
void CL_LogoutEffect (vec3_t org, int type)
|
|
{
|
|
int i;
|
|
vec3_t color;
|
|
|
|
for (i=0 ; i<500 ; i++)
|
|
{
|
|
if (type == MZ_LOGIN)// green
|
|
{
|
|
color[0] = 20;
|
|
color[1] = 200;
|
|
color[2] = 20;
|
|
}
|
|
else if (type == MZ_LOGOUT)// red
|
|
{
|
|
color[0] = 200;
|
|
color[1] = 20;
|
|
color[2] = 20;
|
|
}
|
|
else// yellow
|
|
{
|
|
color[0] = 200;
|
|
color[1] = 200;
|
|
color[2] = 20;
|
|
}
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] - 16 + frand()*32, org[1] - 16 + frand()*32, org[2] - 24 + frand()*56,
|
|
crand()*20, crand()*20, crand()*20,
|
|
0, 0, 0,
|
|
color[0], color[1], color[2],
|
|
0, 0, 0,
|
|
1, -1.0 / (1.0 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_ItemRespawnParticles
|
|
|
|
===============
|
|
*/
|
|
void CL_ItemRespawnParticles (vec3_t org)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i<64 ; i++)
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] + crand()*8, org[1] + crand()*8, org[2] + crand()*8,
|
|
crand()*8, crand()*8, crand()*8,
|
|
0, 0, PARTICLE_GRAVITY*0.2,
|
|
0, 150+rand()*25, 0,
|
|
0, 0, 0,
|
|
1, -1.0 / (1.0 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BigTeleportParticles
|
|
===============
|
|
*/
|
|
void CL_BigTeleportParticles (vec3_t org)
|
|
{
|
|
int i, index;
|
|
float angle, dist;
|
|
static int colortable0[4] = {10,50,150,50};
|
|
static int colortable1[4] = {150,150,50,10};
|
|
static int colortable2[4] = {50,10,10,150};
|
|
|
|
for (i=0; i<(1024/cl_particle_scale->value); i++) // was 4096
|
|
{
|
|
|
|
index = rand()&3;
|
|
angle = M_PI*2*(rand()&1023)/1023.0;
|
|
dist = rand()&31;
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0]+cos(angle)*dist, org[1] + sin(angle)*dist,org[2] + 8 + (rand()%90),
|
|
cos(angle)*(70+(rand()&63)),sin(angle)*(70+(rand()&63)),-100 + (rand()&31),
|
|
-cos(angle)*100, -sin(angle)*100,PARTICLE_GRAVITY*4,
|
|
colortable0[index], colortable1[index], colortable2[index],
|
|
0, 0, 0,
|
|
1, -0.1 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
5, 0.15 / (0.5 + frand()*0.3), // was 2, 0.05
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BlasterParticles
|
|
|
|
Wall impact puffs
|
|
===============
|
|
*/
|
|
#define pBlasterMaxVelocity 100
|
|
#define pBlasterMinSize 1.0
|
|
#define pBlasterMaxSize 5.0
|
|
|
|
void pBlasterThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
vec_t length;
|
|
vec3_t len;
|
|
float clipsize = 1.0;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
*size *= (float)(pBlasterMaxSize/VectorLength(len)) * 1.0/((4-*size));
|
|
*size += *time * p->sizevel;
|
|
|
|
if (*size > pBlasterMaxSize)
|
|
*size = pBlasterMaxSize;
|
|
if (*size < pBlasterMinSize)
|
|
*size = pBlasterMinSize;
|
|
|
|
pBounceThink (p, org, angle, alpha, &clipsize, image, time); // was size
|
|
|
|
length = VectorNormalize(p->vel);
|
|
if (length>pBlasterMaxVelocity)
|
|
VectorScale(p->vel, pBlasterMaxVelocity, p->vel);
|
|
else
|
|
VectorScale(p->vel, length, p->vel);
|
|
|
|
/* vec3_t len;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
*size *= (float)(pBlasterMaxSize/VectorLength(len)) * 1.0/((4-*size));
|
|
if (*size > pBlasterMaxSize)
|
|
*size = pBlasterMaxSize;
|
|
|
|
p->thinknext = true;*/
|
|
}
|
|
|
|
|
|
void pFreonThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
vec_t length;
|
|
vec3_t len;
|
|
float clipsize = 1.0;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
*size *= (float)(pBlasterMaxSize/VectorLength(len)) * 1.0/((4-*size));
|
|
*size += *time * p->sizevel;
|
|
|
|
if (*size > pBlasterMaxSize)
|
|
*size = pBlasterMaxSize;
|
|
if (*size < pBlasterMinSize)
|
|
*size = pBlasterMinSize;
|
|
|
|
pBounceThink (p, org, angle, alpha, &clipsize, image, time); // was size
|
|
|
|
length = VectorNormalize(p->vel);
|
|
if (length>pBlasterMaxVelocity)
|
|
VectorScale(p->vel, pBlasterMaxVelocity, p->vel);
|
|
else
|
|
VectorScale(p->vel, length, p->vel);
|
|
|
|
/* vec3_t len;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
*size *= (float)(pBlasterMaxSize/VectorLength(len)) * 1.0/((4-*size));
|
|
if (*size > pBlasterMaxSize)
|
|
*size = pBlasterMaxSize;
|
|
|
|
p->thinknext = true;*/
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CL_LavaParticles (vec3_t org, vec3_t dir, int count, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
count = 1;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + dir[0]*(1 + random()*64 ),
|
|
org[1] + dir[1]*(1 + random()*64 ),
|
|
org[2] + dir[2]*(1 + random()*16 )
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*75 + crand()*40)*speed, (dir[1]*75 + crand()*40)*speed, (dir[2]*75 + crand()*40)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -0.5 / (0.5 + frand()*0.3), //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
96, -0.01, //size
|
|
particle_smoke,
|
|
PART_GRAVITY,
|
|
NULL,true);
|
|
}
|
|
|
|
speed *= 1.7;
|
|
|
|
count = 1;
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + dir[0]*(1 + random()*48 ),
|
|
org[1] + dir[1]*(1 + random()*48 ),
|
|
org[2] + dir[2]*(1 + random()*16 )
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*75 + crand()*40)*speed, (dir[1]*75 + crand()*40)*speed, (dir[2]*75 + crand()*40)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -0.3, //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
14, -5, //size
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CL_WaterfallParticles (vec3_t org, vec3_t dir, int count, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
count = 1;
|
|
|
|
//the wash on the top.
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + (-32 + random()*64 ),
|
|
org[1] + (-32 + random()*64 ),
|
|
org[2] + (-8 + random()*16 )
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*75 + crand()*64)*speed,
|
|
(dir[1]*75 + crand()*64)*speed,
|
|
(dir[2]*75 + crand()*64)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
0.4, -0.3 / (0.5 + frand()*0.3), //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
16, 96, //size
|
|
particle_smoke,
|
|
PART_GRAVITY,
|
|
NULL,true);
|
|
}
|
|
|
|
count=2;
|
|
|
|
//the main torrent of water.
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + (-6 + random()*12 ),
|
|
org[1] + (-6 + random()*12 ),
|
|
org[2] + (-6 + random()*12 )
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*75 + crand()*8)*speed,
|
|
(dir[1]*75 + crand()*8)*speed,
|
|
(dir[2]*75 + crand()*128)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
0.3, -0.1, //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
32, 16.0, //size
|
|
particle_smoke,
|
|
PART_GRAVITY,
|
|
NULL,true);
|
|
}
|
|
|
|
|
|
|
|
//speed *= 1.7;
|
|
|
|
speed *= (random()*2.9);
|
|
|
|
count = 2;
|
|
|
|
|
|
//the little droplets.
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + (-12 + random()*24 ),
|
|
org[1] + (-12 + random()*24 ),
|
|
org[2] + (-12 + random()*24 )
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
|
|
(dir[0]*4 + crand()*8)*speed,
|
|
(dir[1]*4 + crand()*8)*speed,
|
|
(dir[2]*75 + crand()*40)*speed,
|
|
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -0.15, //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1.8, 0.1, //size -5
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CL_BlasterParticles (vec3_t org, vec3_t dir, int count, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + dir[0]*(1 + random()*3 + pBlasterMaxSize/2.0),
|
|
org[1] + dir[1]*(1 + random()*3 + pBlasterMaxSize/2.0),
|
|
org[2] + dir[2]*(1 + random()*3 + pBlasterMaxSize/2.0)
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*75 + crand()*40)*speed, (dir[1]*75 + crand()*40)*speed, (dir[2]*75 + crand()*40)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -0.5 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
4, -0.5,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
pBlasterThink,true);
|
|
|
|
/* d = rand()&5;
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
org[0]+((rand()&5)-2)+d*dir[0], org[1]+((rand()&5)-2)+d*dir[1], org[2]+((rand()&5)-2)+d*dir[2],
|
|
(dir[0]*50 + crand()*20)*speed, (dir[1]*50 + crand()*20)*speed, (dir[2]*50 + crand()*20)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
4, -1.0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
pBlasterThink,true);*/
|
|
}
|
|
if (p) // added light effect
|
|
addParticleLight (p, 150, 0, ((float)red)/255, ((float)green)/255, ((float)blue)/255);
|
|
}
|
|
|
|
|
|
|
|
void CL_FreonParticles (vec3_t org, vec3_t dir, int count, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0] + dir[0]*(1 + random()*3 + pBlasterMaxSize/2.0),
|
|
org[1] + dir[1]*(1 + random()*3 + pBlasterMaxSize/2.0),
|
|
org[2] + dir[2]*(1 + random()*3 + pBlasterMaxSize/2.0)
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
origin[0], origin[1], origin[2],
|
|
(dir[0]*7 + crand()*4)*speed, (dir[1]*7 + crand()*4)*speed, (dir[2]*7 + crand()*4)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -3,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.01, -0.5,
|
|
particle_smoke,
|
|
0,
|
|
pFreonThink,true);
|
|
|
|
/* d = rand()&5;
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
org[0]+((rand()&5)-2)+d*dir[0], org[1]+((rand()&5)-2)+d*dir[1], org[2]+((rand()&5)-2)+d*dir[2],
|
|
(dir[0]*50 + crand()*20)*speed, (dir[1]*50 + crand()*20)*speed, (dir[2]*50 + crand()*20)*speed,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
4, -1.0,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
pBlasterThink,true);*/
|
|
}
|
|
}
|
|
|
|
|
|
void CL_burpgas(vec3_t org, vec3_t dir, int count,
|
|
int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = 6;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0],
|
|
org[1],
|
|
org[2]
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
|
|
origin[0], origin[1], origin[2],
|
|
|
|
(dir[0]*0.2 + crand()*0.2)*speed, (dir[1]*0.2 + crand()*0.2)*speed, (dir[2]*2 + crand()*1)*speed,
|
|
|
|
0, 0, 0,
|
|
128, 255, 128,
|
|
0, 0, 0,
|
|
0.4, -0.06,//alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.8+crand()*0.2, 8+crand()*0.1, //size
|
|
particle_smoke,
|
|
0,
|
|
NULL,true);
|
|
|
|
}
|
|
}
|
|
|
|
void CL_wineglassbreak (vec3_t org, vec3_t dir, int count,
|
|
int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = 7;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
dir[2] += 5;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0],
|
|
org[1],
|
|
org[2]
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
|
|
origin[0] + crand()*0.3, origin[1]+ crand()*0.3, origin[2]+ crand()*0.3,
|
|
|
|
(dir[0]*0.2 + crand()*2.9)*speed, (dir[1]*0.2 + crand()*2.9)*speed, (dir[2]*2 + crand()*1)*speed,
|
|
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.8, -0.06,//alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.9+crand()*0.7, 0, //size
|
|
particle_glass,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
|
|
origin[0] + crand()*0.3, origin[1]+ crand()*0.3, origin[2]+ crand()*0.3,
|
|
|
|
(dir[0]*0.2 + crand()*3.9)*speed, (dir[1]*0.2 + crand()*3.9)*speed, (dir[2]*2 + crand()*2)*speed,
|
|
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.8, -0.06,//alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.9+crand()*0.7, 0, //size
|
|
particle_glass2,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//zz
|
|
}
|
|
|
|
|
|
|
|
void CL_cigsmoke (vec3_t org, vec3_t dir, int count,
|
|
int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0],
|
|
org[1],
|
|
org[2]
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
|
|
origin[0], origin[1], origin[2],
|
|
|
|
(dir[0]*0.2 + crand()*0.2)*speed, (dir[1]*0.2 + crand()*0.2)*speed, (dir[2]*2 + crand()*1)*speed,
|
|
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.5, -0.06,//alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.05+crand()*0.2, 0.1+crand()*0.1, //size
|
|
particle_smoke,
|
|
0,
|
|
NULL,true);
|
|
|
|
}
|
|
}
|
|
|
|
void CL_cigbigsmoke (vec3_t org, vec3_t dir, int count,
|
|
int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
int i;
|
|
//float d;
|
|
float speed = .75;
|
|
cparticle_t *p;
|
|
vec3_t origin;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
VectorSet(origin,
|
|
org[0],
|
|
org[1],
|
|
org[2]
|
|
);
|
|
|
|
p = setupParticle (
|
|
org[0], org[1], org[2],
|
|
|
|
origin[0], origin[1], origin[2],
|
|
|
|
(dir[0]*0.2 + crand()*0.9)*speed,
|
|
(dir[1]*0.2 + crand()*0.9)*speed,
|
|
(dir[2]*6 + crand()*4)*speed,
|
|
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
0.7, -0.3,//alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.3+crand()*0.5, 1.5+crand()*1.5, //size
|
|
particle_smoke,
|
|
0,
|
|
NULL,true);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BlasterTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_BlasterTrail (vec3_t start, vec3_t end, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int dec;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 4 * cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
// FIXME: this is a really silly way to have a loop
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand(), move[1] + crand(), move[2] + crand(),
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -1.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
4, -6,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_HyperBlasterTrail
|
|
|
|
Hyperblaster particle glow effect
|
|
===============
|
|
*/
|
|
void CL_HyperBlasterTrail (vec3_t start, vec3_t end, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int dec;
|
|
int i;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
VectorMA (move, 0.5, vec, move);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 1 * cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
for (i = 0; i < (18/cl_particle_scale->value); i++)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand(), move[1] + crand(), move[2] + crand(),
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
reddelta, greendelta, bluedelta,
|
|
1, -16.0 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
3, -36,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BlasterTracer
|
|
===============
|
|
*/
|
|
void CL_BlasterTracer (vec3_t origin, vec3_t angle, int red, int green, int blue, float len, float size)
|
|
{
|
|
int i;
|
|
vec3_t dir;
|
|
|
|
AngleVectors (angle, dir, NULL, NULL);
|
|
VectorScale(dir, len,dir);
|
|
|
|
for (i=0;i<3;i++)
|
|
setupParticle (
|
|
dir[0], dir[1], dir[2],
|
|
origin[0], origin[1], origin[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
red, green, blue,
|
|
0, 0, 0,
|
|
1, INSTANT_PARTICLE,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
size, 0,
|
|
particle_generic,
|
|
PART_DIRECTION|PART_INSTANT,
|
|
NULL,0);
|
|
}
|
|
|
|
void CL_HyperBlasterEffect (vec3_t start, vec3_t end, vec3_t angle, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta, float len, float size)
|
|
{
|
|
if (cl_particle_scale->value >= 2)
|
|
CL_BlasterTracer (end, angle, red, green, blue, len, size);
|
|
else
|
|
CL_HyperBlasterTrail (start, end, red, green, blue, reddelta, greendelta, bluedelta);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CL_FreonTrail (vec3_t start, vec3_t end, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int dec;
|
|
int i;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
VectorMA (move, 0.5, vec, move);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 1 * cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
for (i = 0; i < (18/cl_particle_scale->value); i++)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
|
|
|
|
|
|
//origin
|
|
move[0] + crand()*0.5, move[1]+ crand()*0.5, move[2] + crand()*0.5,
|
|
|
|
//velocity
|
|
crand()*3, crand()*3, crand()*3,
|
|
|
|
0, 0, 0,
|
|
100, 210, 250,
|
|
reddelta, greendelta, bluedelta,
|
|
0.99, -16.0 / (0.5 + frand()*0.3), //alpha
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
0.5, -16, //size
|
|
particle_smoke,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
void CL_FreonEffect (vec3_t start, vec3_t end, vec3_t angle, int red, int green, int blue,
|
|
int reddelta, int greendelta, int bluedelta, float len, float size)
|
|
{
|
|
CL_FreonTrail (start, end, red, green, blue, reddelta, greendelta, bluedelta);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_QuadTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_QuadTrail (vec3_t start, vec3_t end)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int dec;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 5;
|
|
VectorScale (vec, 5, vec);
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand()*16, move[1] + crand()*16, move[2] + crand()*16,
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 0,
|
|
0, 0, 200,
|
|
0, 0, 0,
|
|
1, -1.0 / (0.8+frand()*0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_FlagTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_FlagTrail (vec3_t start, vec3_t end, qboolean isred, qboolean isgreen)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int dec;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 5;
|
|
VectorScale (vec, 5, vec);
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand()*16, move[1] + crand()*16, move[2] + crand()*16,
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 0,
|
|
(isred)?255:0, (isgreen)?255:0, (!isred && !isgreen)?255:0,
|
|
0, 0, 0,
|
|
1, -1.0 / (0.8+frand()*0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 0,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_DiminishingTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len, oldlen;
|
|
float dec;
|
|
float orgscale;
|
|
float velscale;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = oldlen = VectorNormalize (vec);
|
|
|
|
dec = (flags & EF_ROCKET) ? 10 : 2;
|
|
dec *= cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
if (old->trailcount > 900)
|
|
{
|
|
orgscale = 4;
|
|
velscale = 15;
|
|
}
|
|
else if (old->trailcount > 800)
|
|
{
|
|
orgscale = 2;
|
|
velscale = 10;
|
|
}
|
|
else
|
|
{
|
|
orgscale = 1;
|
|
velscale = 5;
|
|
}
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
if (!free_particles)
|
|
return;
|
|
|
|
if (flags & EF_ROCKET)
|
|
{
|
|
if (CM_PointContents(move,0) & MASK_WATER)
|
|
setupParticle (
|
|
0, 0, crand()*360,
|
|
move[0], move[1], move[2],
|
|
crand()*9, crand()*9, crand()*9+5,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.75, -0.2 / (1 + frand() * 0.2),
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
1+random()*3, 1,
|
|
particle_bubble,
|
|
PART_TRANS|PART_SHADED,
|
|
pExplosionBubbleThink,true);
|
|
else
|
|
setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
move[0], move[1], move[2],
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 5,
|
|
255, 255, 255,
|
|
-50, -50, -50,
|
|
1, -0.5,
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
5, 15,
|
|
particle_smoke,
|
|
PART_TRANS|PART_SHADED,
|
|
pRotateThink, true);
|
|
}
|
|
else
|
|
{
|
|
// drop less particles as it flies
|
|
//if ((rand()&1023) < old->trailcount)
|
|
if ((rand()&511) < old->trailcount)
|
|
{
|
|
if (flags & EF_GIB)
|
|
{
|
|
if (cl_blood->value > 1)
|
|
p = setupParticle (
|
|
0, 0, random()*360,
|
|
move[0] + crand()*orgscale, move[1] + crand()*orgscale, move[2] + crand()*orgscale,
|
|
crand()*velscale, crand()*velscale, crand()*velscale,
|
|
0, 0, 0,
|
|
255, 0, 0,
|
|
0, 0, 0,
|
|
0.75, -0.75 / (1+frand()*0.4),
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
3 + random()*2, 0,
|
|
particle_blooddrop,
|
|
PART_OVERBRIGHT|PART_GRAVITY|PART_SHADED,
|
|
pBloodThink,true);
|
|
//NULL,0);
|
|
else
|
|
p = setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand()*orgscale, move[1] + crand()*orgscale, move[2] + crand()*orgscale,
|
|
crand()*velscale, crand()*velscale, crand()*velscale,
|
|
0, 0, 0,
|
|
255, 0, 0,
|
|
0, 0, 0,
|
|
1, -1.0 / (1+frand()*0.4),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
5, -1,
|
|
particle_blood,
|
|
PART_GRAVITY|PART_SHADED,
|
|
pBloodThink,true);
|
|
//NULL,0);
|
|
|
|
if (crand() < (double)0.0001F)
|
|
p->flags |= PART_LEAVEMARK;
|
|
}
|
|
else if (flags & EF_GREENGIB)
|
|
{
|
|
p = setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand()*orgscale, move[1] + crand()*orgscale, move[2] + crand()*orgscale,
|
|
crand()*velscale, crand()*velscale, crand()*velscale,
|
|
0, 0, 0,
|
|
255, 180, 50,
|
|
0, 0, 0,
|
|
1, -0.5 / (1+frand()*0.4),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
5, -1,
|
|
particle_blood,
|
|
PART_OVERBRIGHT|PART_GRAVITY|PART_SHADED,
|
|
pBloodThink,true);
|
|
//NULL,0);
|
|
if (crand() < (double)0.0001F)
|
|
p->flags |= PART_LEAVEMARK;
|
|
|
|
}
|
|
else if (flags & EF_GRENADE) // no overbrights on grenade trails
|
|
{
|
|
if (CM_PointContents(move,0) & MASK_WATER)
|
|
setupParticle (
|
|
0, 0, crand()*360,
|
|
move[0], move[1], move[2],
|
|
crand()*9, crand()*9, crand()*9+5,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.75, -0.2 / (1 + frand() * 0.2),
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
1+random()*3, 1,
|
|
particle_bubble,
|
|
PART_TRANS|PART_SHADED,
|
|
pExplosionBubbleThink,true);
|
|
else
|
|
setupParticle (
|
|
crand()*180, crand()*50, 0,
|
|
move[0] + crand()*orgscale, move[1] + crand()*orgscale, move[2] + crand()*orgscale,
|
|
crand()*velscale, crand()*velscale, crand()*velscale,
|
|
0, 0, 20,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.5, -0.35,
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
5, 5,
|
|
particle_smoke,
|
|
PART_TRANS|PART_SHADED,
|
|
pRotateThink,true); //bcccc
|
|
}
|
|
else
|
|
{
|
|
setupParticle (
|
|
crand()*180, crand()*50, 0,
|
|
move[0] + crand()*orgscale, move[1] + crand()*orgscale, move[2] + crand()*orgscale,
|
|
crand()*velscale, crand()*velscale, crand()*velscale,
|
|
0, 0, 20,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.5, -0.5,
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
5, 5,
|
|
particle_smoke,
|
|
PART_OVERBRIGHT|PART_TRANS|PART_SHADED,
|
|
pRotateThink,true);
|
|
}
|
|
}
|
|
|
|
old->trailcount -= 5;
|
|
if (old->trailcount < 100)
|
|
old->trailcount = 100;
|
|
}
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
|
|
{
|
|
float d;
|
|
|
|
// this rotate and negat guarantees a vector
|
|
// not colinear with the original
|
|
right[1] = -forward[0];
|
|
right[2] = forward[1];
|
|
right[0] = forward[2];
|
|
|
|
d = DotProduct (right, forward);
|
|
VectorMA (right, -d, forward, right);
|
|
VectorNormalize (right);
|
|
CrossProduct (right, forward, up);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_RocketTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len, totallen;
|
|
float dec;
|
|
|
|
// smoke
|
|
CL_DiminishingTrail (start, end, old, EF_ROCKET);
|
|
|
|
// fire
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
totallen = len = VectorNormalize (vec);
|
|
|
|
dec = 1*cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
if (!free_particles)
|
|
return;
|
|
|
|
//falling particles
|
|
if ( (rand()&7) == 0)
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand()*5, move[1] + crand()*5, move[2] + crand()*5,
|
|
crand()*20, crand()*20, crand()*20,
|
|
0, 0, 20,
|
|
255, 255, 200,
|
|
0, -50, 0,
|
|
1, -1.0 / (1+frand()*0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
2, -2,
|
|
particle_blaster,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
totallen = len = VectorNormalize (vec);
|
|
dec = 1.5*cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
/* len = totallen;
|
|
VectorCopy (start, move);
|
|
dec = 1.5;//*cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);*/
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
//flame
|
|
setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
move[0], move[1], move[2],
|
|
crand()*5, crand()*5, crand()*5,
|
|
0, 0, 5,
|
|
255, 225, 200,
|
|
-50, -50, -50,
|
|
0.75, -3,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
5, 5,
|
|
particle_inferno,
|
|
0,
|
|
pRotateThink, true);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
FartherPoint
|
|
Returns true if the first vector
|
|
is farther from the viewpoint.
|
|
===============
|
|
*/
|
|
qboolean FartherPoint (vec3_t pt1, vec3_t pt2)
|
|
{
|
|
vec3_t distance1, distance2;
|
|
|
|
VectorSubtract(pt1, cl.refdef.vieworg, distance1);
|
|
VectorSubtract(pt2, cl.refdef.vieworg, distance2);
|
|
return (VectorLength(distance1) > VectorLength(distance2));
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_RailTrail
|
|
===============
|
|
*/
|
|
#define DEVRAILSTEPS 2
|
|
//this is the length of each piece...
|
|
#define RAILTRAILSPACE 15
|
|
|
|
void CL_RailSprial (vec3_t start, vec3_t end, qboolean isRed)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
vec3_t right, up;
|
|
int i;
|
|
float d, c, s;
|
|
vec3_t dir;
|
|
|
|
// Draw from closest point
|
|
if (FartherPoint(start, end)) {
|
|
VectorCopy (end, move);
|
|
VectorSubtract (start, end, vec);
|
|
}
|
|
else {
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
}
|
|
len = VectorNormalize (vec);
|
|
len = min (len, cl_rail_length->value); // cap length
|
|
MakeNormalVectors (vec, right, up);
|
|
|
|
VectorScale(vec, cl_rail_space->value*cl_particle_scale->value, vec);
|
|
|
|
for (i=0; i<len; i += cl_rail_space->value*cl_particle_scale->value)
|
|
{
|
|
d = i * 0.1;
|
|
c = cos(d);
|
|
s = sin(d);
|
|
|
|
VectorScale (right, c, dir);
|
|
VectorMA (dir, s, up, dir);
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + dir[0]*3, move[1] + dir[1]*3, move[2] + dir[2]*3,
|
|
dir[0]*6, dir[1]*6, dir[2]*6,
|
|
0, 0, 0,
|
|
(isRed)?255:cl_railred->value, (isRed)?20:cl_railgreen->value, (isRed)?20:cl_railblue->value,
|
|
0, 0, 0,
|
|
1, -1.0,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
3, 0,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
void pDevRailThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
int i;
|
|
vec3_t len;
|
|
VectorSubtract(p->angle, org, len);
|
|
|
|
*size *= (float)(SplashSize/VectorLength(len)) * 0.5/((4-*size));
|
|
if (*size > SplashSize)
|
|
*size = SplashSize;
|
|
|
|
//setting up angle for sparks
|
|
{
|
|
float time1, time2;
|
|
|
|
time1 = *time;
|
|
time2 = time1*time1;
|
|
|
|
for (i=0;i<2;i++)
|
|
angle[i] = 3*(p->vel[i]*time1 + (p->accel[i])*time2);
|
|
angle[2] = 3*(p->vel[2]*time1 + (p->accel[2]-PARTICLE_GRAVITY)*time2);
|
|
}
|
|
|
|
p->thinknext = true;
|
|
}
|
|
|
|
void CL_DevRailTrail (vec3_t start, vec3_t end, qboolean isRed)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec, point;
|
|
float len;
|
|
int dec, i=0;
|
|
|
|
// Draw from closest point
|
|
if (FartherPoint(start, end)) {
|
|
VectorCopy (end, move);
|
|
VectorSubtract (start, end, vec);
|
|
}
|
|
else {
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
}
|
|
len = VectorNormalize (vec);
|
|
len = min (len, cl_rail_length->value); // cap length
|
|
VectorCopy(vec, point);
|
|
|
|
dec = 4;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
// FIXME: this is a really silly way to have a loop
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
i++;
|
|
|
|
if (i>=DEVRAILSTEPS)
|
|
{
|
|
for (i=3;i>0;i--)
|
|
setupParticle (
|
|
point[0], point[1], point[2],
|
|
move[0], move[1], move[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
(isRed)?255:cl_railred->value, (isRed)?20:cl_railgreen->value, (isRed)?20:cl_railblue->value,
|
|
0, -90, -30,
|
|
0.75, -.75,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
dec*DEVRAILSTEPS*TWOTHIRDS, 0,
|
|
particle_beam2,
|
|
PART_DIRECTION,
|
|
NULL,0);
|
|
}
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0], move[1], move[2],
|
|
crand()*10, crand()*10, crand()*10+20,
|
|
0, 0, 0,
|
|
(isRed)?255:cl_railred->value, (isRed)?20:cl_railgreen->value, (isRed)?20:cl_railblue->value,
|
|
0, 0, 0,
|
|
1, -0.75 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
2, -0.25,
|
|
0,
|
|
PART_GRAVITY|PART_SPARK,
|
|
pDevRailThink,true);
|
|
|
|
setupParticle (
|
|
crand()*180, crand()*100, 0,
|
|
move[0], move[1], move[2],
|
|
crand()*10, crand()*10, crand()*10+20,
|
|
0, 0, 5,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.25, -0.25,
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
5, 10,
|
|
particle_smoke,
|
|
PART_TRANS|PART_GRAVITY|PART_OVERBRIGHT,
|
|
pRotateThink, true);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
void CL_RailTrail (vec3_t start, vec3_t end, qboolean isRed)
|
|
{
|
|
vec3_t move, last;
|
|
vec3_t vec, point;
|
|
//vec3_t right, up;
|
|
int i;
|
|
int beamred, beamgreen, beamblue;
|
|
float len;//, dec;
|
|
qboolean colored = (cl_railtype->value!=0);
|
|
|
|
#ifdef DECALS // railgun impact decal
|
|
VectorSubtract (end, start, vec);
|
|
VectorNormalize(vec);
|
|
CL_ParticleRailDecal (end, vec, 7, isRed);
|
|
#endif
|
|
|
|
if (cl_railtype->value == 2)
|
|
{
|
|
CL_DevRailTrail (start, end, isRed);
|
|
return;
|
|
}
|
|
// Draw from closest point
|
|
if (FartherPoint(start, end)) {
|
|
VectorCopy (end, move);
|
|
VectorSubtract (start, end, vec);
|
|
}
|
|
else {
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
}
|
|
len = VectorNormalize (vec);
|
|
if (cl_railtype->value == 0)
|
|
len = min (len, cl_rail_length->value); // cap length
|
|
VectorCopy (vec, point);
|
|
VectorScale (vec, RAILTRAILSPACE, vec);
|
|
//MakeNormalVectors (vec, right, up);
|
|
|
|
if (colored) {
|
|
if (isRed) {
|
|
beamred = 255;
|
|
beamgreen = beamblue = 20;
|
|
}
|
|
else {
|
|
beamred = cl_railred->value;
|
|
beamgreen = cl_railgreen->value;
|
|
beamblue = cl_railblue->value;
|
|
}
|
|
}
|
|
else
|
|
beamred = beamgreen = beamblue = 255;
|
|
|
|
while (len > 0)
|
|
{
|
|
VectorCopy (move, last);
|
|
VectorAdd (move, vec, move);
|
|
|
|
len -= RAILTRAILSPACE;
|
|
|
|
for (i=0;i<3;i++)
|
|
setupParticle (
|
|
last[0], last[1], last[2],
|
|
move[0], move[1], move[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
beamred, beamgreen, beamblue,
|
|
0, 0, 0,
|
|
0.75, -0.75,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
RAILTRAILSPACE*TWOTHIRDS, (colored)?0:-5,
|
|
particle_beam2,
|
|
PART_BEAM,
|
|
NULL,0);
|
|
}
|
|
if (cl_railtype->value == 0)
|
|
CL_RailSprial (start, end, isRed);
|
|
}
|
|
|
|
|
|
// RAFAEL
|
|
/*
|
|
===============
|
|
CL_IonripperTrail
|
|
===============
|
|
*/
|
|
void CL_IonripperTrail (vec3_t start, vec3_t ent)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
vec3_t leftdir,up;
|
|
float len;
|
|
int dec;
|
|
int left = 0;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (ent, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
MakeNormalVectors (vec, leftdir, up);
|
|
|
|
dec = 3*cl_particle_scale->value;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0], move[1], move[2],
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
255, 75, 0,
|
|
0, 0, 0,
|
|
0.75, -1.0 / (0.3 + frand() * 0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
3, 0, // was dec
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BubbleTrail
|
|
|
|
===============
|
|
*/
|
|
void CL_BubbleTrail (vec3_t start, vec3_t end)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
float len;
|
|
int i;
|
|
float dec, size;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 32;
|
|
VectorScale (vec, dec, vec);
|
|
|
|
for (i=0 ; i<len ; i+=dec)
|
|
{
|
|
size = (frand()>0.25)? 1 : (frand()>0.5) ? 2 : (frand()>0.75) ? 3 : 4;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0]+crand()*2, move[1]+crand()*2, move[2]+crand()*2,
|
|
crand()*5, crand()*5, crand()*5+6,
|
|
0, 0, 0,
|
|
255, 255, 255,
|
|
0, 0, 0,
|
|
0.75, -0.5 / (1 + frand() * 0.2),
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
size, 1,
|
|
particle_bubble,
|
|
PART_TRANS|PART_SHADED,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_FlyParticles
|
|
===============
|
|
*/
|
|
#define BEAMLENGTH 16
|
|
|
|
|
|
void CL_FlyParticles (vec3_t origin, int count)
|
|
{
|
|
int i;
|
|
float angle;
|
|
float sr, sp, sy, cr, cp, cy;
|
|
vec3_t forward;
|
|
float dist = 64;
|
|
float ltime;
|
|
|
|
|
|
if (count > NUMVERTEXNORMALS)
|
|
count = NUMVERTEXNORMALS;
|
|
|
|
if (!avelocities[0][0])
|
|
{
|
|
for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
|
|
avelocities[0][i] = (rand()&255) * 0.01;
|
|
}
|
|
|
|
|
|
ltime = (float)cl.time / 1000.0;
|
|
for (i=0 ; i<count ; i+=2)
|
|
{
|
|
angle = ltime * avelocities[i][0];
|
|
sy = sin(angle);
|
|
cy = cos(angle);
|
|
angle = ltime * avelocities[i][1];
|
|
sp = sin(angle);
|
|
cp = cos(angle);
|
|
angle = ltime * avelocities[i][2];
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
forward[0] = cp*cy;
|
|
forward[1] = cp*sy;
|
|
forward[2] = -sp;
|
|
|
|
dist = sin(ltime + i)*64;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH,origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH,
|
|
origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
1, -100,
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
1+sin(i+ltime), 1,
|
|
particle_generic,
|
|
PART_TRANS,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CL_FlyEffect
|
|
===============
|
|
*/
|
|
void CL_FlyEffect (centity_t *ent, vec3_t origin)
|
|
{
|
|
int n;
|
|
int count;
|
|
int starttime;
|
|
|
|
if (ent->fly_stoptime < cl.time)
|
|
{
|
|
starttime = cl.time;
|
|
ent->fly_stoptime = cl.time + 60000;
|
|
}
|
|
else
|
|
{
|
|
starttime = ent->fly_stoptime - 60000;
|
|
}
|
|
|
|
n = cl.time - starttime;
|
|
if (n < 20000)
|
|
count = n * 162 / 20000.0;
|
|
else
|
|
{
|
|
n = ent->fly_stoptime - cl.time;
|
|
if (n < 20000)
|
|
count = n * 162 / 20000.0;
|
|
else
|
|
count = 162;
|
|
}
|
|
|
|
CL_FlyParticles (origin, count);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BfgParticles
|
|
===============
|
|
*/
|
|
void pBFGThink (cparticle_t *p, vec3_t org, vec3_t angle, float *alpha, float *size, int *image, float *time)
|
|
{
|
|
vec3_t len;
|
|
VectorSubtract(p->angle, p->org, len);
|
|
|
|
*size = (float)((300/VectorLength(len))*0.75);
|
|
}
|
|
|
|
#define BEAMLENGTH 16
|
|
|
|
void CL_BfgParticles (entity_t *ent)
|
|
{
|
|
int i;
|
|
cparticle_t *p;
|
|
float angle;
|
|
float sr, sp, sy, cr, cp, cy;
|
|
vec3_t forward;
|
|
float dist = 64, dist2;
|
|
vec3_t v;
|
|
float ltime;
|
|
|
|
if (!avelocities[0][0])
|
|
{
|
|
for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
|
|
avelocities[0][i] = (rand()&255) * 0.01;
|
|
}
|
|
|
|
|
|
ltime = (float)cl.time / 1000.0;
|
|
for (i=0 ; i<NUMVERTEXNORMALS ; i++)
|
|
{
|
|
angle = ltime * avelocities[i][0];
|
|
sy = sin(angle);
|
|
cy = cos(angle);
|
|
angle = ltime * avelocities[i][1];
|
|
sp = sin(angle);
|
|
cp = cos(angle);
|
|
angle = ltime * avelocities[i][2];
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
forward[0] = cp*cy;
|
|
forward[1] = cp*sy;
|
|
forward[2] = -sp;
|
|
|
|
dist2 = dist;
|
|
dist = sin(ltime + i)*64;
|
|
|
|
p = setupParticle (
|
|
ent->origin[0], ent->origin[1], ent->origin[2],
|
|
ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH,ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH,
|
|
ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH,
|
|
0, 0, 0,
|
|
0, 0, 0,
|
|
50, 200*dist2, 20,
|
|
0, 0, 0,
|
|
1, -100,
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 1,
|
|
particle_generic,
|
|
0,
|
|
pBFGThink, true);
|
|
|
|
if (!p)
|
|
return;
|
|
|
|
VectorSubtract (p->org, ent->origin, v);
|
|
dist = VectorLength(v) / 90.0;
|
|
}
|
|
}
|
|
|
|
|
|
// RAFAEL
|
|
/*
|
|
===============
|
|
CL_TrapParticles
|
|
===============
|
|
*/
|
|
void CL_TrapParticles (entity_t *ent)
|
|
{
|
|
vec3_t move;
|
|
vec3_t vec;
|
|
vec3_t start, end;
|
|
float len;
|
|
int dec;
|
|
|
|
ent->origin[2]-=14;
|
|
VectorCopy (ent->origin, start);
|
|
VectorCopy (ent->origin, end);
|
|
end[2]+=64;
|
|
|
|
VectorCopy (start, move);
|
|
VectorSubtract (end, start, vec);
|
|
len = VectorNormalize (vec);
|
|
|
|
dec = 5;
|
|
VectorScale (vec, 5, vec);
|
|
|
|
// FIXME: this is a really silly way to have a loop
|
|
while (len > 0)
|
|
{
|
|
len -= dec;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
move[0] + crand(), move[1] + crand(), move[2] + crand(),
|
|
crand()*15, crand()*15, crand()*15,
|
|
0, 0, PARTICLE_GRAVITY,
|
|
230+crand()*25, 125+crand()*25, 25+crand()*25,
|
|
0, 0, 0,
|
|
1, -1.0 / (0.3+frand()*0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
3, -3,
|
|
particle_generic,
|
|
0,
|
|
NULL,0);
|
|
|
|
VectorAdd (move, vec, move);
|
|
}
|
|
|
|
{
|
|
int i, j, k;
|
|
float vel;
|
|
vec3_t dir;
|
|
vec3_t org;
|
|
|
|
|
|
ent->origin[2]+=14;
|
|
VectorCopy (ent->origin, org);
|
|
|
|
|
|
for (i=-2 ; i<=2 ; i+=4)
|
|
for (j=-2 ; j<=2 ; j+=4)
|
|
for (k=-2 ; k<=4 ; k+=4)
|
|
{
|
|
|
|
dir[0] = j * 8;
|
|
dir[1] = i * 8;
|
|
dir[2] = k * 8;
|
|
|
|
VectorNormalize (dir);
|
|
vel = 50 + rand()&63;
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] + i + ((rand()&23) * crand()), org[1] + j + ((rand()&23) * crand()), org[2] + k + ((rand()&23) * crand()),
|
|
dir[0]*vel, dir[1]*vel, dir[2]*vel,
|
|
0, 0, 0,
|
|
230+crand()*25, 125+crand()*25, 25+crand()*25,
|
|
0, 0, 0,
|
|
1, -1.0 / (0.3+frand()*0.2),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 1,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_BFGExplosionParticles
|
|
===============
|
|
*/
|
|
//FIXME combined with CL_ExplosionParticles
|
|
void CL_BFGExplosionParticles (vec3_t org)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0] + ((rand()%32)-16), org[1] + ((rand()%32)-16), org[2] + ((rand()%32)-16),
|
|
(rand()%150)-75, (rand()%150)-75, (rand()%150)-75,
|
|
0, 0, 0,
|
|
50, 100+rand()*50, 0, //Knightmare- made more green
|
|
0, 0, 0,
|
|
1, -0.8 / (0.5 + frand()*0.3),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
10, -10,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_TeleportParticles
|
|
|
|
===============
|
|
*/
|
|
void CL_TeleportParticles (vec3_t org)
|
|
{
|
|
int i, j, k;
|
|
float vel;
|
|
vec3_t dir;
|
|
|
|
for (i=-16 ; i<=16 ; i+=4)
|
|
for (j=-16 ; j<=16 ; j+=4)
|
|
for (k=-16 ; k<=32 ; k+=4)
|
|
{
|
|
dir[0] = j*16;
|
|
dir[1] = i*16;
|
|
dir[2] = k*16;
|
|
|
|
VectorNormalize (dir);
|
|
vel = 150 + (rand()&63);
|
|
|
|
setupParticle (
|
|
0, 0, 0,
|
|
org[0]+i+(rand()&3), org[1]+j+(rand()&3), org[2]+k+(rand()&3),
|
|
dir[0]*vel, dir[1]*vel, dir[2]*vel,
|
|
0, 0, 0,
|
|
200 + 55*rand(), 200 + 55*rand(), 200 + 55*rand(),
|
|
0, 0, 0,
|
|
1, -1.0 / (0.3 + (rand()&7) * 0.02),
|
|
GL_SRC_ALPHA, GL_ONE,
|
|
1, 3,
|
|
particle_generic,
|
|
PART_GRAVITY,
|
|
NULL,0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CL_AddParticles
|
|
===============
|
|
*/
|
|
|
|
void CL_AddParticles (void)
|
|
{
|
|
cparticle_t *p, *next;
|
|
float alpha, size, light;
|
|
float time=0, time2;
|
|
vec3_t org, color, angle;
|
|
int i, image, flags, decals;
|
|
cparticle_t *active, *tail;
|
|
|
|
active = NULL;
|
|
tail = NULL;
|
|
decals = 0;
|
|
|
|
for (p=active_particles; p; p=next)
|
|
{
|
|
next = p->next;
|
|
flags = p->flags;
|
|
|
|
// PMM - added INSTANT_PARTICLE handling for heat beam
|
|
if (p->alphavel != INSTANT_PARTICLE)
|
|
{
|
|
time = (cl.time - p->time)*0.001;
|
|
alpha = p->alpha + time*p->alphavel;
|
|
#ifdef DECALS
|
|
if (flags&PART_DECAL)
|
|
{
|
|
if (decals >= r_decals->value || alpha <= 0)
|
|
{ // faded out
|
|
p->alpha = 0;
|
|
p->flags = 0;
|
|
ClearDecalPoly (p->decal); // flag decal chain for cleaning
|
|
p->decalnum = 0;
|
|
p->decal = NULL;
|
|
p->next = free_particles;
|
|
free_particles = p;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (alpha <= 0)
|
|
{ // faded out
|
|
p->alpha = 0;
|
|
p->flags = 0;
|
|
p->next = free_particles;
|
|
free_particles = p;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alpha = p->alpha;
|
|
}
|
|
|
|
p->next = NULL;
|
|
if (!tail)
|
|
active = tail = p;
|
|
else
|
|
{
|
|
tail->next = p;
|
|
tail = p;
|
|
}
|
|
|
|
if (alpha > 1.0)
|
|
alpha = 1;
|
|
if (alpha < 0.0)
|
|
alpha = 0;
|
|
|
|
time2 = time*time;
|
|
image = p->image;
|
|
|
|
for (i=0;i<3;i++)
|
|
{
|
|
color[i] = p->color[i] + p->colorvel[i]*time;
|
|
if (color[i]>255) color[i]=255;
|
|
if (color[i]<0) color[i]=0;
|
|
|
|
angle[i] = p->angle[i];
|
|
org[i] = p->org[i] + p->vel[i]*time + p->accel[i]*time2;
|
|
}
|
|
|
|
if (p->flags&PART_GRAVITY)
|
|
org[2]+=time2*-PARTICLE_GRAVITY;
|
|
|
|
size = p->size + p->sizevel*time;
|
|
|
|
for (i=0;i<P_LIGHTS_MAX;i++)
|
|
{
|
|
const cplight_t *plight = &p->lights[i];
|
|
if (plight->isactive)
|
|
{
|
|
light = plight->light*alpha + plight->lightvel*time;
|
|
V_AddLight (org, light, plight->lightcol[0], plight->lightcol[1], plight->lightcol[2]);
|
|
}
|
|
}
|
|
|
|
if (p->thinknext && p->think)
|
|
{
|
|
p->thinknext=false;
|
|
p->think(p, org, angle, &alpha, &size, &image, &time);
|
|
}
|
|
|
|
#ifdef DECALS
|
|
if (flags & PART_DECAL)
|
|
{
|
|
decalpolys_t *d;
|
|
if (p->decalnum > 0 && p->decal)
|
|
for (d=p->decal; d; d=d->nextpoly)
|
|
V_AddDecal (org, angle, color, alpha, p->blendfunc_src, p->blendfunc_dst, size, image, flags, d);
|
|
else
|
|
V_AddDecal (org, angle, color, alpha, p->blendfunc_src, p->blendfunc_dst, size, image, flags, NULL);
|
|
decals++;
|
|
}
|
|
else
|
|
#endif
|
|
V_AddParticle (org, angle, color, alpha, p->blendfunc_src, p->blendfunc_dst, size, image, flags);
|
|
|
|
if (p->alphavel == INSTANT_PARTICLE)
|
|
{
|
|
p->alphavel = 0.0;
|
|
p->alpha = 0.0;
|
|
}
|
|
VectorCopy(org, p->oldorg);
|
|
}
|
|
|
|
active_particles = active;
|
|
#ifdef DECALS
|
|
CleanDecalPolys(); // clean up active_decals linked list
|
|
#endif
|
|
}
|
|
|
|
|
|
void CL_ClearDlights (void);
|
|
void CL_ClearLightStyles (void);
|
|
|
|
/*
|
|
==============
|
|
CL_ClearEffects
|
|
|
|
==============
|
|
*/
|
|
void CL_ClearEffects (void)
|
|
{
|
|
CL_ClearParticles ();
|
|
#ifdef DECALS
|
|
CL_ClearAllDecalPolys ();
|
|
#endif
|
|
CL_ClearDlights ();
|
|
CL_ClearLightStyles ();
|
|
}
|
|
|
|
#ifdef DECALS
|
|
/*
|
|
==============
|
|
CL_UnclipDecals
|
|
Removes decal fragment pointers
|
|
and resets decal fragment data
|
|
Called during a vid_restart
|
|
==============
|
|
*/
|
|
void CL_UnclipDecals (void)
|
|
{
|
|
cparticle_t *p;
|
|
|
|
//Com_Printf ("Unclipping decals\n");
|
|
for (p=active_particles; p; p=p->next)
|
|
{
|
|
p->decalnum = 0;
|
|
p->decal = NULL;
|
|
}
|
|
CL_ClearAllDecalPolys();
|
|
}
|
|
|
|
/*
|
|
==============
|
|
CL_ReclipDecals
|
|
Re-clips all decals
|
|
Called during a vid_restart
|
|
==============
|
|
*/
|
|
void CL_ReclipDecals (void)
|
|
{
|
|
cparticle_t *p;
|
|
vec3_t dir;
|
|
|
|
//Com_Printf ("Reclipping decals\n");
|
|
for (p=active_particles; p; p=p->next)
|
|
{
|
|
p->decalnum = 0;
|
|
p->decal = NULL;
|
|
if (p->flags & PART_DECAL)
|
|
{
|
|
AngleVectors (p->angle, dir, NULL, NULL);
|
|
VectorNegate(dir, dir);
|
|
clipDecal(p, p->size, -p->angle[2], p->org, dir);
|
|
|
|
if (!p->decalnum) // kill on viewframe
|
|
p->alpha = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|