/* 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_newfx.c -- MORE entity effects parsing and management #include "client.h" extern cparticle_t *active_particles, *free_particles; extern cparticle_t particles[MAX_PARTICLES]; extern int cl_numparticles; extern cvar_t *vid_ref; extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up); #ifdef QMAX 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, 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); #endif /* ====== vectoangles2 - this is duplicated in the game DLL, but I need it here. ====== */ void vectoangles2 (vec3_t value1, vec3_t angles) { float forward; float yaw, pitch; if (value1[1] == 0 && value1[0] == 0) { yaw = 0; if (value1[2] > 0) pitch = 90; else pitch = 270; } else { // PMM - fixed to correct for pitch of 0 if (value1[0]) yaw = (atan2(value1[1], value1[0]) * 180 / M_PI); else if (value1[1] > 0) yaw = 90; else yaw = 270; if (yaw < 0) yaw += 360; forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]); pitch = (atan2(value1[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; } angles[PITCH] = -pitch; angles[YAW] = yaw; angles[ROLL] = 0; } //============= //============= void CL_Flashlight (int ent, vec3_t pos) { cdlight_t *dl; dl = CL_AllocDlight (ent); VectorCopy (pos, dl->origin); dl->radius = 400; dl->minlight = 250; dl->die = cl.time + 100; dl->color[0] = 1; dl->color[1] = 1; dl->color[2] = 1; } /* ====== CL_ColorFlash - flash of light ====== */ void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b) { cdlight_t *dl; if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0))) { intensity = -intensity; r = -r; g = -g; b = -b; } dl = CL_AllocDlight (ent); VectorCopy (pos, dl->origin); dl->radius = intensity; dl->minlight = 250; dl->die = cl.time + 100; dl->color[0] = r; dl->color[1] = g; dl->color[2] = b; } /* ====== CL_DebugTrail ====== */ void CL_DebugTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; #ifndef QMAX cparticle_t *p; #endif float dec; vec3_t right, up; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); // VectorScale(vec, RT2_SKIP, vec); // dec = 1.0; // dec = 0.75; dec = 3; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; #ifdef QMAX setupParticle ( 0, 0, 0, move[0], move[1], move[2], 0, 0, 0, 0, 0, 0, 50, 50, 255, 0, 0, 0, 1, -0.75, 7.5, 0, particle_generic, 0, NULL,0); #else if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); VectorClear (p->vel); p->alpha = 1.0; p->alphavel = -0.1; // p->alphavel = 0; p->color = 0x74 + (rand()&7); VectorCopy (move, p->org); /* for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*2; p->vel[j] = crand()*3; p->accel[j] = 0; } */ #endif VectorAdd (move, vec, move); } } /* =============== CL_SmokeTrail =============== */ void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorScale (vec, spacing, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= spacing; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.5); #ifndef QMAX p->color = colorStart + (rand() % colorRun); #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*3; p->accel[j] = 0; } p->vel[2] = 20 + crand()*5; VectorAdd (move, vec, move); } } void CL_ForceWall (vec3_t start, vec3_t end, int color8) { vec3_t move; vec3_t vec; #ifdef QMAX vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)}; #else int j; cparticle_t *p; #endif float len; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorScale (vec, 4, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= 4; if (!free_particles) return; if (frand() > 0.3) { #ifdef QMAX setupParticle ( 0, 0, 0, move[0] + crand()*3, move[1] + crand()*3, move[2] + crand()*3, 0, 0, -40 - (crand()*10), 0, 0, 0, color[0]+5, color[1]+5, color[2]+5, 0, 0, 0, 1, -1.0 / (3.0+frand()*0.5), 5, 0, particle_generic, 0, NULL,0); #else p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (3.0+frand()*0.5); p->color = color8; for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*3; p->accel[j] = 0; } p->vel[0] = 0; p->vel[1] = 0; p->vel[2] = -40 - (crand()*10); #endif } VectorAdd (move, vec, move); } } void CL_FlameEffects (centity_t *ent, vec3_t origin) { int n, count; int j; cparticle_t *p; count = rand() & 0xF; for(n=0;nnext; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.2); #ifndef QMAX p->color = 226 + (rand() % 4); #endif for (j=0 ; j<3 ; j++) { p->org[j] = origin[j] + crand()*5; p->vel[j] = crand()*5; } p->vel[2] = crand() * -10; p->accel[2] = -PARTICLE_GRAVITY; } count = rand() & 0x7; for(n=0;nnext; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.5); #ifndef QMAX p->color = 0 + (rand() % 4); #endif for (j=0 ; j<3 ; j++) { p->org[j] = origin[j] + crand()*3; } p->vel[2] = 20 + crand()*5; } } /* =============== CL_GenericParticleEffect =============== */ void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel) { int i, j; cparticle_t *p; float d; for (i=0 ; inext; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX if (numcolors > 1) p->color = color + (rand() & numcolors); else p->color = color; #endif d = rand() & dirspread; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j]; p->vel[j] = crand()*20; } p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; // VectorCopy (accel, p->accel); p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*alphavel); // p->alphavel = alphavel; } } /* =============== CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns) =============== */ void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist) { vec3_t move; vec3_t vec; float len; int i; #ifndef QMAX int j; cparticle_t *p; #endif float dec; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); dec = dist; VectorScale (vec, dec, vec); for (i=0 ; i0.25)? 1 : (frand()>0.5) ? 2 : (frand()>0.75) ? 3 : 4, 1, particle_bubble, PART_TRANS|PART_SHADED, NULL,0); #else if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (1+frand()*0.1); p->color = 4 + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*2; p->vel[j] = crand()*10; } p->org[2] -= 4; // p->vel[2] += 6; p->vel[2] += 20; #endif VectorAdd (move, vec, move); } } //#define CORKSCREW 1 //#define DOUBLE_SCREW 1 #define RINGS 1 //#define SPRAY 1 #ifdef CORKSCREW void CL_Heatbeam (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j,k; cparticle_t *p; vec3_t right, up; int i; float d, c, s; vec3_t dir; float ltime; float step = 5.0; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // MakeNormalVectors (vec, right, up); VectorCopy (cl.v_right, right); VectorCopy (cl.v_up, up); VectorMA (move, -1, right, move); VectorMA (move, -1, up, move); VectorScale (vec, step, vec); ltime = (float) cl.time/1000.0; // for (i=0 ; inext; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); p->alpha = 0.5; // p->alphavel = -1.0 / (1+frand()*0.2); // only last one frame! p->alphavel = INSTANT_PARTICLE; // p->color = 0x74 + (rand()&7); // p->color = 223 - (rand()&7); #ifndef QMAX p->color = 223; #endif // p->color = 240; // trim it so it looks like it's starting at the origin if (i < 10) { VectorScale (right, c*(i/10.0)*k, dir); VectorMA (dir, s*(i/10.0)*k, up, dir); } else { VectorScale (right, c*k, dir); VectorMA (dir, s*k, up, dir); } #ifdef QMAX setupParticle ( 0, 0, 0, move[0]+dir[0]*3, move[1]+dir[1]*3, move[2]+dir[2]*3, 0, 0, 0, 0, 0, 0, 200+rand()*50, 200+rand()*25, rand()*50, 0, 0, 0, 0.5, -1000.0, 3, 1, particle_blaster, 0, NULL,0); #else for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; // p->vel[j] = dir[j]*6; p->vel[j] = 0; } #endif #ifdef DOUBLE_SCREW } #endif VectorAdd (move, vec, move); } } #endif #ifdef RINGS //void CL_Heatbeam (vec3_t start, vec3_t end) void CL_Heatbeam (vec3_t start, vec3_t forward) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; vec3_t right, up; int i; float c, s; vec3_t dir; float ltime; float step = 32.0, rstep; float start_pt; float rot; float variance; vec3_t end; VectorMA (start, 4096, forward, end); VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // FIXME - pmm - these might end up using old values? // MakeNormalVectors (vec, right, up); VectorCopy (cl.v_right, right); VectorCopy (cl.v_up, up); if (vidref_val == VIDREF_GL) { // GL mode VectorMA (move, -0.5, right, move); VectorMA (move, -0.5, up, move); } // otherwise assume SOFT ltime = (float) cl.time/1000.0; start_pt = fmod(ltime*96.0,step); VectorMA (move, start_pt, vec, move); VectorScale (vec, step, vec); // Com_Printf ("%f\n", ltime); rstep = M_PI/10.0; for (i=start_pt ; istep*5) // don't bother after the 5th ring break; for (rot = 0; rot < M_PI*2; rot += rstep) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); // rot+= fmod(ltime, 12.0)*M_PI; // c = cos(rot)/2.0; // s = sin(rot)/2.0; // variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2; variance = 0.5; c = cos(rot)*variance; s = sin(rot)*variance; // trim it so it looks like it's starting at the origin if (i < 10) { VectorScale (right, c*(i/10.0), dir); VectorMA (dir, s*(i/10.0), up, dir); } else { VectorScale (right, c, dir); VectorMA (dir, s, up, dir); } p->alpha = 0.5; // p->alphavel = -1.0 / (1+frand()*0.2); p->alphavel = -1000.0; // p->color = 0x74 + (rand()&7); #ifndef QMAX p->color = 223 - (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; // p->vel[j] = dir[j]*6; p->vel[j] = 0; } } VectorAdd (move, vec, move); } } #endif #ifdef SPRAY void CL_Heatbeam (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; vec3_t forward, right, up; int i; float d, c, s; vec3_t dir; float ltime; float step = 32.0, rstep; float start_pt; float rot; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // MakeNormalVectors (vec, right, up); VectorCopy (cl.v_forward, forward); VectorCopy (cl.v_right, right); VectorCopy (cl.v_up, up); VectorMA (move, -0.5, right, move); VectorMA (move, -0.5, up, move); for (i=0; i<8; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); d = crand()*M_PI; c = cos(d)*30; s = sin(d)*30; p->alpha = 1.0; p->alphavel = -5.0 / (1+frand()); #ifndef QMAX p->color = 223 - (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j]; } VectorScale (vec, 450, p->vel); VectorMA (p->vel, c, right, p->vel); VectorMA (p->vel, s, up, p->vel); } /* ltime = (float) cl.time/1000.0; start_pt = fmod(ltime*16.0,step); VectorMA (move, start_pt, vec, move); VectorScale (vec, step, vec); // Com_Printf ("%f\n", ltime); rstep = M_PI/12.0; for (i=start_pt ; istep*5) // don't bother after the 5th ring break; for (rot = 0; rot < M_PI*2; rot += rstep) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); // rot+= fmod(ltime, 12.0)*M_PI; // c = cos(rot)/2.0; // s = sin(rot)/2.0; c = cos(rot)/1.5; s = sin(rot)/1.5; // trim it so it looks like it's starting at the origin if (i < 10) { VectorScale (right, c*(i/10.0), dir); VectorMA (dir, s*(i/10.0), up, dir); } else { VectorScale (right, c, dir); VectorMA (dir, s, up, dir); } p->alpha = 0.5; // p->alphavel = -1.0 / (1+frand()*0.2); p->alphavel = -1000.0; // p->color = 0x74 + (rand()&7); #ifndef QMAX p->color = 223 - (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; // p->vel[j] = dir[j]*6; p->vel[j] = 0; } } VectorAdd (move, vec, move); } */ } #endif /* =============== CL_ParticleSteamEffect Puffs with velocity along direction, with some randomness thrown in =============== */ void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; // vectoangles2 (dir, angle_dir); // AngleVectors (angle_dir, f, r, u); MakeNormalVectors (dir, r, u); for (i=0 ; inext; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = color + (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, magnitude, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY/2; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } } void CL_ParticleSteamEffect2 (cl_sustain_t *self) //vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; vec3_t dir; // vectoangles2 (dir, angle_dir); // AngleVectors (angle_dir, f, r, u); VectorCopy (self->dir, dir); MakeNormalVectors (dir, r, u); for (i=0 ; icount ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = self->color + (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = self->org[j] + self->magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, self->magnitude, p->vel); d = crand()*self->magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*self->magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY/2; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } self->nextthink += self->thinkinterval; } /* =============== CL_TrackerTrail =============== */ void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor) { vec3_t move; vec3_t vec; vec3_t forward,right,up,angle_dir; float len; int j; cparticle_t *p; int dec; float dist; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorCopy(vec, forward); vectoangles2 (forward, angle_dir); AngleVectors (angle_dir, forward, right, up); dec = 3; VectorScale (vec, 3, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -2.0; #ifndef QMAX p->color = particleColor; #endif dist = DotProduct(move, forward); VectorMA(move, 8 * cos(dist), up, p->org); for (j=0 ; j<3 ; j++) { // p->org[j] = move[j] + crand(); p->vel[j] = 0; p->accel[j] = 0; } p->vel[2] = 5; VectorAdd (move, vec, move); } } void CL_Tracker_Shell(vec3_t origin) { vec3_t dir; int i; cparticle_t *p; for(i=0;i<300;i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = INSTANT_PARTICLE; #ifndef QMAX p->color = 0; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorMA(origin, 40, dir, p->org); } } void CL_MonsterPlasma_Shell(vec3_t origin) { vec3_t dir; int i; cparticle_t *p; for(i=0;i<40;i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = INSTANT_PARTICLE; #ifndef QMAX p->color = 0xe0; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorMA(origin, 10, dir, p->org); // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org); } } void CL_Widowbeamout (cl_sustain_t *self) { vec3_t dir; int i; cparticle_t *p; #ifndef QMAX static int colortable[4] = {2*8,13*8,21*8,18*8}; #endif float ratio; ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0); for(i=0;i<300;i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = INSTANT_PARTICLE; #ifndef QMAX p->color = colortable[rand()&3]; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorMA(self->org, (45.0 * ratio), dir, p->org); // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org); } } void CL_Nukeblast (cl_sustain_t *self) { vec3_t dir; int i; cparticle_t *p; #ifndef QMAX static int colortable[4] = {110, 112, 114, 116}; #endif float ratio; ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0); for(i=0;i<700;i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = INSTANT_PARTICLE; #ifndef QMAX p->color = colortable[rand()&3]; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorMA(self->org, (200.0 * ratio), dir, p->org); // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org); } } void CL_WidowSplash (vec3_t org) { #ifndef QMAX static int colortable[4] = {2*8,13*8,21*8,18*8}; #endif int i; cparticle_t *p; vec3_t dir; for (i=0 ; i<256 ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = colortable[rand()&3]; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorMA(org, 45.0, dir, p->org); VectorMA(vec3_origin, 40.0, dir, p->vel); p->accel[0] = p->accel[1] = 0; p->alpha = 1.0; p->alphavel = -0.8 / (0.5 + frand()*0.3); } } void CL_Tracker_Explode(vec3_t origin) { vec3_t dir, backdir; int i; cparticle_t *p; for(i=0;i<300;i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0; #ifndef QMAX p->color = 0; #endif dir[0] = crand(); dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); VectorScale(dir, -1, backdir); VectorMA(origin, 64, dir, p->org); VectorScale(backdir, 64, p->vel); } } /* =============== CL_TagTrail =============== */ void CL_TagTrail (vec3_t start, vec3_t end, float color) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; int dec; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); dec = 5; VectorScale (vec, 5, vec); while (len >= 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (0.8+frand()*0.2); #ifndef QMAX p->color = color; #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*16; p->vel[j] = crand()*5; p->accel[j] = 0; } VectorAdd (move, vec, move); } } /* =============== CL_ColorExplosionParticles =============== */ void CL_ColorExplosionParticles (vec3_t org, int color8, int run) { int i; #ifdef QMAX vec3_t color = { color8red(color8), color8green(color8), color8blue(color8)}; #else int j; cparticle_t *p; #endif for (i=0 ; i<128 ; i++) { #ifdef QMAX setupParticle ( 0, 0, 0, org[0] + ((rand()%32)-16), org[1] + ((rand()%32)-16), org[2] + ((rand()%32)-16), (rand()%256)-128, (rand()%256)-128, (rand()%256)-128, 0, 0, 20, color[0] + (rand() % run), color[1] + (rand() % run), color[2] + (rand() % run), 0, 0, 0, 1.0, -0.4 / (0.6 + frand()*0.2), 2, 1, particle_generic, 0, NULL,0); #else if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; p->color = color8 + (rand() % run); for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()%32)-16); p->vel[j] = (rand()%256)-128; } p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; p->alpha = 1.0; p->alphavel = -0.4 / (0.6 + frand()*0.2); #endif } } /* =============== CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity =============== */ #ifdef QMAX void pRotateThink (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]; p->thinknext=true; } #endif void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; MakeNormalVectors (dir, r, u); for (i=0 ; inext; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = color + (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, magnitude, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = p->accel[2] = 0; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } } /* =============== CL_BlasterParticles2 Wall impact puffs (Green) =============== */ void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color) { int i, j; cparticle_t *p; float d; int count; count = 40; for (i=0 ; inext; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = color + (rand()&7); #endif d = rand()&15; for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j]; p->vel[j] = dir[j] * 30 + crand()*40; } p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } } /* =============== CL_BlasterTrail2 Green! =============== */ void CL_BlasterTrail2 (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; int dec; 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; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0; p->alphavel = -1.0 / (0.3+frand()*0.2); #ifndef QMAX p->color = 0xd0; #endif for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand(); p->vel[j] = crand()*5; p->accel[j] = 0; } VectorAdd (move, vec, move); } }