Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cg_particles.c (40763B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // Rafael particles
     23 // cg_particles.c  
     24 
     25 #include "cg_local.h"
     26 
     27 #define BLOODRED	2
     28 #define EMISIVEFADE	3
     29 #define GREY75		4
     30 
     31 typedef struct particle_s
     32 {
     33 	struct particle_s	*next;
     34 
     35 	float		time;
     36 	float		endtime;
     37 
     38 	vec3_t		org;
     39 	vec3_t		vel;
     40 	vec3_t		accel;
     41 	int			color;
     42 	float		colorvel;
     43 	float		alpha;
     44 	float		alphavel;
     45 	int			type;
     46 	qhandle_t	pshader;
     47 	
     48 	float		height;
     49 	float		width;
     50 				
     51 	float		endheight;
     52 	float		endwidth;
     53 	
     54 	float		start;
     55 	float		end;
     56 
     57 	float		startfade;
     58 	qboolean	rotate;
     59 	int			snum;
     60 	
     61 	qboolean	link;
     62 
     63 	// Ridah
     64 	int			shaderAnim;
     65 	int			roll;
     66 
     67 	int			accumroll;
     68 
     69 } cparticle_t;
     70 
     71 typedef enum
     72 {
     73 	P_NONE,
     74 	P_WEATHER,
     75 	P_FLAT,
     76 	P_SMOKE,
     77 	P_ROTATE,
     78 	P_WEATHER_TURBULENT,
     79 	P_ANIM,	// Ridah
     80 	P_BAT,
     81 	P_BLEED,
     82 	P_FLAT_SCALEUP,
     83 	P_FLAT_SCALEUP_FADE,
     84 	P_WEATHER_FLURRY,
     85 	P_SMOKE_IMPACT,
     86 	P_BUBBLE,
     87 	P_BUBBLE_TURBULENT,
     88 	P_SPRITE
     89 } particle_type_t;
     90 
     91 #define	MAX_SHADER_ANIMS		32
     92 #define	MAX_SHADER_ANIM_FRAMES	64
     93 
     94 static char *shaderAnimNames[MAX_SHADER_ANIMS] = {
     95 	"explode1",
     96 	"blacksmokeanim",
     97 	"twiltb2",
     98 	"expblue",
     99 	"blacksmokeanimb",	// uses 'explode1' sequence
    100 	"blood",
    101 	NULL
    102 };
    103 static qhandle_t shaderAnims[MAX_SHADER_ANIMS][MAX_SHADER_ANIM_FRAMES];
    104 static int	shaderAnimCounts[MAX_SHADER_ANIMS] = {
    105 	23,
    106 	25,
    107 	45,
    108 	25,
    109 	23,
    110 	5,
    111 };
    112 static float	shaderAnimSTRatio[MAX_SHADER_ANIMS] = {
    113 	1.405f,
    114 	1.0f,
    115 	1.0f,
    116 	1.0f,
    117 	1.0f,
    118 	1.0f,
    119 };
    120 static int	numShaderAnims;
    121 // done.
    122 
    123 #define		PARTICLE_GRAVITY	40
    124 #define		MAX_PARTICLES	1024 * 8
    125 
    126 cparticle_t	*active_particles, *free_particles;
    127 cparticle_t	particles[MAX_PARTICLES];
    128 int		cl_numparticles = MAX_PARTICLES;
    129 
    130 qboolean		initparticles = qfalse;
    131 vec3_t			vforward, vright, vup;
    132 vec3_t			rforward, rright, rup;
    133 
    134 float			oldtime;
    135 
    136 /*
    137 ===============
    138 CL_ClearParticles
    139 ===============
    140 */
    141 void CG_ClearParticles (void)
    142 {
    143 	int		i;
    144 
    145 	memset( particles, 0, sizeof(particles) );
    146 
    147 	free_particles = &particles[0];
    148 	active_particles = NULL;
    149 
    150 	for (i=0 ;i<cl_numparticles ; i++)
    151 	{
    152 		particles[i].next = &particles[i+1];
    153 		particles[i].type = 0;
    154 	}
    155 	particles[cl_numparticles-1].next = NULL;
    156 
    157 	oldtime = cg.time;
    158 
    159 	// Ridah, init the shaderAnims
    160 	for (i=0; shaderAnimNames[i]; i++) {
    161 		int j;
    162 
    163 		for (j=0; j<shaderAnimCounts[i]; j++) {
    164 			shaderAnims[i][j] = trap_R_RegisterShader( va("%s%i", shaderAnimNames[i], j+1) );
    165 		}
    166 	}
    167 	numShaderAnims = i;
    168 	// done.
    169 
    170 	initparticles = qtrue;
    171 }
    172 
    173 
    174 /*
    175 =====================
    176 CG_AddParticleToScene
    177 =====================
    178 */
    179 void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
    180 {
    181 
    182 	vec3_t		point;
    183 	polyVert_t	verts[4];
    184 	float		width;
    185 	float		height;
    186 	float		time, time2;
    187 	float		ratio;
    188 	float		invratio;
    189 	vec3_t		color;
    190 	polyVert_t	TRIverts[3];
    191 	vec3_t		rright2, rup2;
    192 
    193 	if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
    194 		|| p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
    195 	{// create a front facing polygon
    196 			
    197 		if (p->type != P_WEATHER_FLURRY)
    198 		{
    199 			if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
    200 			{
    201 				if (org[2] > p->end)			
    202 				{	
    203 					p->time = cg.time;	
    204 					VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
    205 									
    206 					p->org[2] = ( p->start + crandom () * 4 );
    207 					
    208 					
    209 					if (p->type == P_BUBBLE_TURBULENT)
    210 					{
    211 						p->vel[0] = crandom() * 4;
    212 						p->vel[1] = crandom() * 4;
    213 					}
    214 				
    215 				}
    216 			}
    217 			else
    218 			{
    219 				if (org[2] < p->end)			
    220 				{	
    221 					p->time = cg.time;	
    222 					VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground
    223 									
    224 					while (p->org[2] < p->end) 
    225 					{
    226 						p->org[2] += (p->start - p->end); 
    227 					}
    228 					
    229 					
    230 					if (p->type == P_WEATHER_TURBULENT)
    231 					{
    232 						p->vel[0] = crandom() * 16;
    233 						p->vel[1] = crandom() * 16;
    234 					}
    235 				
    236 				}
    237 			}
    238 			
    239 
    240 			// Rafael snow pvs check
    241 			if (!p->link)
    242 				return;
    243 
    244 			p->alpha = 1;
    245 		}
    246 		
    247 		// Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
    248 		if (Distance( cg.snap->ps.origin, org ) > 1024) {
    249 			return;
    250 		}
    251 		// done.
    252 	
    253 		if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
    254 		{
    255 			VectorMA (org, -p->height, vup, point);	
    256 			VectorMA (point, -p->width, vright, point);	
    257 			VectorCopy (point, verts[0].xyz);	
    258 			verts[0].st[0] = 0;	
    259 			verts[0].st[1] = 0;	
    260 			verts[0].modulate[0] = 255;	
    261 			verts[0].modulate[1] = 255;	
    262 			verts[0].modulate[2] = 255;	
    263 			verts[0].modulate[3] = 255 * p->alpha;	
    264 
    265 			VectorMA (org, -p->height, vup, point);	
    266 			VectorMA (point, p->width, vright, point);	
    267 			VectorCopy (point, verts[1].xyz);	
    268 			verts[1].st[0] = 0;	
    269 			verts[1].st[1] = 1;	
    270 			verts[1].modulate[0] = 255;	
    271 			verts[1].modulate[1] = 255;	
    272 			verts[1].modulate[2] = 255;	
    273 			verts[1].modulate[3] = 255 * p->alpha;	
    274 
    275 			VectorMA (org, p->height, vup, point);	
    276 			VectorMA (point, p->width, vright, point);	
    277 			VectorCopy (point, verts[2].xyz);	
    278 			verts[2].st[0] = 1;	
    279 			verts[2].st[1] = 1;	
    280 			verts[2].modulate[0] = 255;	
    281 			verts[2].modulate[1] = 255;	
    282 			verts[2].modulate[2] = 255;	
    283 			verts[2].modulate[3] = 255 * p->alpha;	
    284 
    285 			VectorMA (org, p->height, vup, point);	
    286 			VectorMA (point, -p->width, vright, point);	
    287 			VectorCopy (point, verts[3].xyz);	
    288 			verts[3].st[0] = 1;	
    289 			verts[3].st[1] = 0;	
    290 			verts[3].modulate[0] = 255;	
    291 			verts[3].modulate[1] = 255;	
    292 			verts[3].modulate[2] = 255;	
    293 			verts[3].modulate[3] = 255 * p->alpha;	
    294 		}
    295 		else
    296 		{
    297 			VectorMA (org, -p->height, vup, point);	
    298 			VectorMA (point, -p->width, vright, point);	
    299 			VectorCopy( point, TRIverts[0].xyz );
    300 			TRIverts[0].st[0] = 1;
    301 			TRIverts[0].st[1] = 0;
    302 			TRIverts[0].modulate[0] = 255;
    303 			TRIverts[0].modulate[1] = 255;
    304 			TRIverts[0].modulate[2] = 255;
    305 			TRIverts[0].modulate[3] = 255 * p->alpha;	
    306 
    307 			VectorMA (org, p->height, vup, point);	
    308 			VectorMA (point, -p->width, vright, point);	
    309 			VectorCopy (point, TRIverts[1].xyz);	
    310 			TRIverts[1].st[0] = 0;
    311 			TRIverts[1].st[1] = 0;
    312 			TRIverts[1].modulate[0] = 255;
    313 			TRIverts[1].modulate[1] = 255;
    314 			TRIverts[1].modulate[2] = 255;
    315 			TRIverts[1].modulate[3] = 255 * p->alpha;	
    316 
    317 			VectorMA (org, p->height, vup, point);	
    318 			VectorMA (point, p->width, vright, point);	
    319 			VectorCopy (point, TRIverts[2].xyz);	
    320 			TRIverts[2].st[0] = 0;
    321 			TRIverts[2].st[1] = 1;
    322 			TRIverts[2].modulate[0] = 255;
    323 			TRIverts[2].modulate[1] = 255;
    324 			TRIverts[2].modulate[2] = 255;
    325 			TRIverts[2].modulate[3] = 255 * p->alpha;	
    326 		}
    327 	
    328 	}
    329 	else if (p->type == P_SPRITE)
    330 	{
    331 		vec3_t	rr, ru;
    332 		vec3_t	rotate_ang;
    333 
    334 		VectorSet (color, 1.0, 1.0, 1.0);
    335 		time = cg.time - p->time;
    336 		time2 = p->endtime - p->time;
    337 		ratio = time / time2;
    338 
    339 		width = p->width + ( ratio * ( p->endwidth - p->width) );
    340 		height = p->height + ( ratio * ( p->endheight - p->height) );
    341 
    342 		if (p->roll) {
    343 			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
    344 			rotate_ang[ROLL] += p->roll;
    345 			AngleVectors ( rotate_ang, NULL, rr, ru);
    346 		}
    347 
    348 		if (p->roll) {
    349 			VectorMA (org, -height, ru, point);	
    350 			VectorMA (point, -width, rr, point);	
    351 		} else {
    352 			VectorMA (org, -height, vup, point);	
    353 			VectorMA (point, -width, vright, point);	
    354 		}
    355 		VectorCopy (point, verts[0].xyz);	
    356 		verts[0].st[0] = 0;	
    357 		verts[0].st[1] = 0;	
    358 		verts[0].modulate[0] = 255;	
    359 		verts[0].modulate[1] = 255;	
    360 		verts[0].modulate[2] = 255;	
    361 		verts[0].modulate[3] = 255;
    362 
    363 		if (p->roll) {
    364 			VectorMA (point, 2*height, ru, point);	
    365 		} else {
    366 			VectorMA (point, 2*height, vup, point);	
    367 		}
    368 		VectorCopy (point, verts[1].xyz);	
    369 		verts[1].st[0] = 0;	
    370 		verts[1].st[1] = 1;	
    371 		verts[1].modulate[0] = 255;	
    372 		verts[1].modulate[1] = 255;	
    373 		verts[1].modulate[2] = 255;	
    374 		verts[1].modulate[3] = 255;	
    375 
    376 		if (p->roll) {
    377 			VectorMA (point, 2*width, rr, point);	
    378 		} else {
    379 			VectorMA (point, 2*width, vright, point);	
    380 		}
    381 		VectorCopy (point, verts[2].xyz);	
    382 		verts[2].st[0] = 1;	
    383 		verts[2].st[1] = 1;	
    384 		verts[2].modulate[0] = 255;	
    385 		verts[2].modulate[1] = 255;	
    386 		verts[2].modulate[2] = 255;	
    387 		verts[2].modulate[3] = 255;	
    388 
    389 		if (p->roll) {
    390 			VectorMA (point, -2*height, ru, point);	
    391 		} else {
    392 			VectorMA (point, -2*height, vup, point);	
    393 		}
    394 		VectorCopy (point, verts[3].xyz);	
    395 		verts[3].st[0] = 1;	
    396 		verts[3].st[1] = 0;	
    397 		verts[3].modulate[0] = 255;	
    398 		verts[3].modulate[1] = 255;	
    399 		verts[3].modulate[2] = 255;	
    400 		verts[3].modulate[3] = 255;	
    401 	}
    402 	else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
    403 	{// create a front rotating facing polygon
    404 
    405 		if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
    406 			return;
    407 		}
    408 
    409 		if (p->color == BLOODRED)
    410 			VectorSet (color, 0.22f, 0.0f, 0.0f);
    411 		else if (p->color == GREY75)
    412 		{
    413 			float	len;
    414 			float	greyit;
    415 			float	val;
    416 			len = Distance (cg.snap->ps.origin, org);
    417 			if (!len)
    418 				len = 1;
    419 
    420 			val = 4096/len;
    421 			greyit = 0.25 * val;
    422 			if (greyit > 0.5)
    423 				greyit = 0.5;
    424 
    425 			VectorSet (color, greyit, greyit, greyit);
    426 		}
    427 		else
    428 			VectorSet (color, 1.0, 1.0, 1.0);
    429 
    430 		time = cg.time - p->time;
    431 		time2 = p->endtime - p->time;
    432 		ratio = time / time2;
    433 		
    434 		if (cg.time > p->startfade)
    435 		{
    436 			invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );
    437 
    438 			if (p->color == EMISIVEFADE)
    439 			{
    440 				float fval;
    441 				fval = (invratio * invratio);
    442 				if (fval < 0)
    443 					fval = 0;
    444 				VectorSet (color, fval , fval , fval );
    445 			}
    446 			invratio *= p->alpha;
    447 		}
    448 		else 
    449 			invratio = 1 * p->alpha;
    450 
    451 		if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
    452 			invratio = 1;
    453 
    454 		if (invratio > 1)
    455 			invratio = 1;
    456 	
    457 		width = p->width + ( ratio * ( p->endwidth - p->width) );
    458 		height = p->height + ( ratio * ( p->endheight - p->height) );
    459 
    460 		if (p->type != P_SMOKE_IMPACT)
    461 		{
    462 			vec3_t temp;
    463 
    464 			vectoangles (rforward, temp);
    465 			p->accumroll += p->roll;
    466 			temp[ROLL] += p->accumroll * 0.1;
    467 			AngleVectors ( temp, NULL, rright2, rup2);
    468 		}
    469 		else
    470 		{
    471 			VectorCopy (rright, rright2);
    472 			VectorCopy (rup, rup2);
    473 		}
    474 		
    475 		if (p->rotate)
    476 		{
    477 			VectorMA (org, -height, rup2, point);	
    478 			VectorMA (point, -width, rright2, point);	
    479 		}
    480 		else
    481 		{
    482 			VectorMA (org, -p->height, vup, point);	
    483 			VectorMA (point, -p->width, vright, point);	
    484 		}
    485 		VectorCopy (point, verts[0].xyz);	
    486 		verts[0].st[0] = 0;	
    487 		verts[0].st[1] = 0;	
    488 		verts[0].modulate[0] = 255 * color[0];	
    489 		verts[0].modulate[1] = 255 * color[1];	
    490 		verts[0].modulate[2] = 255 * color[2];	
    491 		verts[0].modulate[3] = 255 * invratio;	
    492 
    493 		if (p->rotate)
    494 		{
    495 			VectorMA (org, -height, rup2, point);	
    496 			VectorMA (point, width, rright2, point);	
    497 		}
    498 		else
    499 		{
    500 			VectorMA (org, -p->height, vup, point);	
    501 			VectorMA (point, p->width, vright, point);	
    502 		}
    503 		VectorCopy (point, verts[1].xyz);	
    504 		verts[1].st[0] = 0;	
    505 		verts[1].st[1] = 1;	
    506 		verts[1].modulate[0] = 255 * color[0];	
    507 		verts[1].modulate[1] = 255 * color[1];	
    508 		verts[1].modulate[2] = 255 * color[2];	
    509 		verts[1].modulate[3] = 255 * invratio;	
    510 
    511 		if (p->rotate)
    512 		{
    513 			VectorMA (org, height, rup2, point);	
    514 			VectorMA (point, width, rright2, point);	
    515 		}
    516 		else
    517 		{
    518 			VectorMA (org, p->height, vup, point);	
    519 			VectorMA (point, p->width, vright, point);	
    520 		}
    521 		VectorCopy (point, verts[2].xyz);	
    522 		verts[2].st[0] = 1;	
    523 		verts[2].st[1] = 1;	
    524 		verts[2].modulate[0] = 255 * color[0];	
    525 		verts[2].modulate[1] = 255 * color[1];	
    526 		verts[2].modulate[2] = 255 * color[2];	
    527 		verts[2].modulate[3] = 255 * invratio;	
    528 
    529 		if (p->rotate)
    530 		{
    531 			VectorMA (org, height, rup2, point);	
    532 			VectorMA (point, -width, rright2, point);	
    533 		}
    534 		else
    535 		{
    536 			VectorMA (org, p->height, vup, point);	
    537 			VectorMA (point, -p->width, vright, point);	
    538 		}
    539 		VectorCopy (point, verts[3].xyz);	
    540 		verts[3].st[0] = 1;	
    541 		verts[3].st[1] = 0;	
    542 		verts[3].modulate[0] = 255 * color[0];	
    543 		verts[3].modulate[1] = 255 * color[1];	
    544 		verts[3].modulate[2] = 255 * color[2];	
    545 		verts[3].modulate[3] = 255  * invratio;	
    546 		
    547 	}
    548 	else if (p->type == P_BLEED)
    549 	{
    550 		vec3_t	rr, ru;
    551 		vec3_t	rotate_ang;
    552 		float	alpha;
    553 
    554 		alpha = p->alpha;
    555 		
    556 		if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO )
    557 			alpha = 1;
    558 
    559 		if (p->roll) 
    560 		{
    561 			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
    562 			rotate_ang[ROLL] += p->roll;
    563 			AngleVectors ( rotate_ang, NULL, rr, ru);
    564 		}
    565 		else
    566 		{
    567 			VectorCopy (vup, ru);
    568 			VectorCopy (vright, rr);
    569 		}
    570 
    571 		VectorMA (org, -p->height, ru, point);	
    572 		VectorMA (point, -p->width, rr, point);	
    573 		VectorCopy (point, verts[0].xyz);	
    574 		verts[0].st[0] = 0;	
    575 		verts[0].st[1] = 0;	
    576 		verts[0].modulate[0] = 111;	
    577 		verts[0].modulate[1] = 19;	
    578 		verts[0].modulate[2] = 9;	
    579 		verts[0].modulate[3] = 255 * alpha;	
    580 
    581 		VectorMA (org, -p->height, ru, point);	
    582 		VectorMA (point, p->width, rr, point);	
    583 		VectorCopy (point, verts[1].xyz);	
    584 		verts[1].st[0] = 0;	
    585 		verts[1].st[1] = 1;	
    586 		verts[1].modulate[0] = 111;	
    587 		verts[1].modulate[1] = 19;	
    588 		verts[1].modulate[2] = 9;	
    589 		verts[1].modulate[3] = 255 * alpha;	
    590 
    591 		VectorMA (org, p->height, ru, point);	
    592 		VectorMA (point, p->width, rr, point);	
    593 		VectorCopy (point, verts[2].xyz);	
    594 		verts[2].st[0] = 1;	
    595 		verts[2].st[1] = 1;	
    596 		verts[2].modulate[0] = 111;	
    597 		verts[2].modulate[1] = 19;	
    598 		verts[2].modulate[2] = 9;	
    599 		verts[2].modulate[3] = 255 * alpha;	
    600 
    601 		VectorMA (org, p->height, ru, point);	
    602 		VectorMA (point, -p->width, rr, point);	
    603 		VectorCopy (point, verts[3].xyz);	
    604 		verts[3].st[0] = 1;	
    605 		verts[3].st[1] = 0;	
    606 		verts[3].modulate[0] = 111;	
    607 		verts[3].modulate[1] = 19;	
    608 		verts[3].modulate[2] = 9;	
    609 		verts[3].modulate[3] = 255 * alpha;	
    610 
    611 	}
    612 	else if (p->type == P_FLAT_SCALEUP)
    613 	{
    614 		float width, height;
    615 		float sinR, cosR;
    616 
    617 		if (p->color == BLOODRED)
    618 			VectorSet (color, 1, 1, 1);
    619 		else
    620 			VectorSet (color, 0.5, 0.5, 0.5);
    621 		
    622 		time = cg.time - p->time;
    623 		time2 = p->endtime - p->time;
    624 		ratio = time / time2;
    625 
    626 		width = p->width + ( ratio * ( p->endwidth - p->width) );
    627 		height = p->height + ( ratio * ( p->endheight - p->height) );
    628 
    629 		if (width > p->endwidth)
    630 			width = p->endwidth;
    631 
    632 		if (height > p->endheight)
    633 			height = p->endheight;
    634 
    635 		sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
    636 		cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);
    637 
    638 		VectorCopy (org, verts[0].xyz);	
    639 		verts[0].xyz[0] -= sinR;
    640 		verts[0].xyz[1] -= cosR;
    641 		verts[0].st[0] = 0;	
    642 		verts[0].st[1] = 0;	
    643 		verts[0].modulate[0] = 255 * color[0];	
    644 		verts[0].modulate[1] = 255 * color[1];	
    645 		verts[0].modulate[2] = 255 * color[2];	
    646 		verts[0].modulate[3] = 255;	
    647 
    648 		VectorCopy (org, verts[1].xyz);	
    649 		verts[1].xyz[0] -= cosR;	
    650 		verts[1].xyz[1] += sinR;	
    651 		verts[1].st[0] = 0;	
    652 		verts[1].st[1] = 1;	
    653 		verts[1].modulate[0] = 255 * color[0];	
    654 		verts[1].modulate[1] = 255 * color[1];	
    655 		verts[1].modulate[2] = 255 * color[2];	
    656 		verts[1].modulate[3] = 255;	
    657 
    658 		VectorCopy (org, verts[2].xyz);	
    659 		verts[2].xyz[0] += sinR;	
    660 		verts[2].xyz[1] += cosR;	
    661 		verts[2].st[0] = 1;	
    662 		verts[2].st[1] = 1;	
    663 		verts[2].modulate[0] = 255 * color[0];	
    664 		verts[2].modulate[1] = 255 * color[1];	
    665 		verts[2].modulate[2] = 255 * color[2];	
    666 		verts[2].modulate[3] = 255;	
    667 
    668 		VectorCopy (org, verts[3].xyz);	
    669 		verts[3].xyz[0] += cosR;	
    670 		verts[3].xyz[1] -= sinR;	
    671 		verts[3].st[0] = 1;	
    672 		verts[3].st[1] = 0;	
    673 		verts[3].modulate[0] = 255 * color[0];	
    674 		verts[3].modulate[1] = 255 * color[1];	
    675 		verts[3].modulate[2] = 255 * color[2];	
    676 		verts[3].modulate[3] = 255;		
    677 	}
    678 	else if (p->type == P_FLAT)
    679 	{
    680 
    681 		VectorCopy (org, verts[0].xyz);	
    682 		verts[0].xyz[0] -= p->height;	
    683 		verts[0].xyz[1] -= p->width;	
    684 		verts[0].st[0] = 0;	
    685 		verts[0].st[1] = 0;	
    686 		verts[0].modulate[0] = 255;	
    687 		verts[0].modulate[1] = 255;	
    688 		verts[0].modulate[2] = 255;	
    689 		verts[0].modulate[3] = 255;	
    690 
    691 		VectorCopy (org, verts[1].xyz);	
    692 		verts[1].xyz[0] -= p->height;	
    693 		verts[1].xyz[1] += p->width;	
    694 		verts[1].st[0] = 0;	
    695 		verts[1].st[1] = 1;	
    696 		verts[1].modulate[0] = 255;	
    697 		verts[1].modulate[1] = 255;	
    698 		verts[1].modulate[2] = 255;	
    699 		verts[1].modulate[3] = 255;	
    700 
    701 		VectorCopy (org, verts[2].xyz);	
    702 		verts[2].xyz[0] += p->height;	
    703 		verts[2].xyz[1] += p->width;	
    704 		verts[2].st[0] = 1;	
    705 		verts[2].st[1] = 1;	
    706 		verts[2].modulate[0] = 255;	
    707 		verts[2].modulate[1] = 255;	
    708 		verts[2].modulate[2] = 255;	
    709 		verts[2].modulate[3] = 255;	
    710 
    711 		VectorCopy (org, verts[3].xyz);	
    712 		verts[3].xyz[0] += p->height;	
    713 		verts[3].xyz[1] -= p->width;	
    714 		verts[3].st[0] = 1;	
    715 		verts[3].st[1] = 0;	
    716 		verts[3].modulate[0] = 255;	
    717 		verts[3].modulate[1] = 255;	
    718 		verts[3].modulate[2] = 255;	
    719 		verts[3].modulate[3] = 255;	
    720 
    721 	}
    722 	// Ridah
    723 	else if (p->type == P_ANIM) {
    724 		vec3_t	rr, ru;
    725 		vec3_t	rotate_ang;
    726 		int i, j;
    727 
    728 		time = cg.time - p->time;
    729 		time2 = p->endtime - p->time;
    730 		ratio = time / time2;
    731 		if (ratio >= 1.0f) {
    732 			ratio = 0.9999f;
    733 		}
    734 
    735 		width = p->width + ( ratio * ( p->endwidth - p->width) );
    736 		height = p->height + ( ratio * ( p->endheight - p->height) );
    737 
    738 		// if we are "inside" this sprite, don't draw
    739 		if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
    740 			return;
    741 		}
    742 
    743 		i = p->shaderAnim;
    744 		j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
    745 		p->pshader = shaderAnims[i][j];
    746 
    747 		if (p->roll) {
    748 			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
    749 			rotate_ang[ROLL] += p->roll;
    750 			AngleVectors ( rotate_ang, NULL, rr, ru);
    751 		}
    752 
    753 		if (p->roll) {
    754 			VectorMA (org, -height, ru, point);	
    755 			VectorMA (point, -width, rr, point);	
    756 		} else {
    757 			VectorMA (org, -height, vup, point);	
    758 			VectorMA (point, -width, vright, point);	
    759 		}
    760 		VectorCopy (point, verts[0].xyz);	
    761 		verts[0].st[0] = 0;	
    762 		verts[0].st[1] = 0;	
    763 		verts[0].modulate[0] = 255;	
    764 		verts[0].modulate[1] = 255;	
    765 		verts[0].modulate[2] = 255;	
    766 		verts[0].modulate[3] = 255;
    767 
    768 		if (p->roll) {
    769 			VectorMA (point, 2*height, ru, point);	
    770 		} else {
    771 			VectorMA (point, 2*height, vup, point);	
    772 		}
    773 		VectorCopy (point, verts[1].xyz);	
    774 		verts[1].st[0] = 0;	
    775 		verts[1].st[1] = 1;	
    776 		verts[1].modulate[0] = 255;	
    777 		verts[1].modulate[1] = 255;	
    778 		verts[1].modulate[2] = 255;	
    779 		verts[1].modulate[3] = 255;	
    780 
    781 		if (p->roll) {
    782 			VectorMA (point, 2*width, rr, point);	
    783 		} else {
    784 			VectorMA (point, 2*width, vright, point);	
    785 		}
    786 		VectorCopy (point, verts[2].xyz);	
    787 		verts[2].st[0] = 1;	
    788 		verts[2].st[1] = 1;	
    789 		verts[2].modulate[0] = 255;	
    790 		verts[2].modulate[1] = 255;	
    791 		verts[2].modulate[2] = 255;	
    792 		verts[2].modulate[3] = 255;	
    793 
    794 		if (p->roll) {
    795 			VectorMA (point, -2*height, ru, point);	
    796 		} else {
    797 			VectorMA (point, -2*height, vup, point);	
    798 		}
    799 		VectorCopy (point, verts[3].xyz);	
    800 		verts[3].st[0] = 1;	
    801 		verts[3].st[1] = 0;	
    802 		verts[3].modulate[0] = 255;	
    803 		verts[3].modulate[1] = 255;	
    804 		verts[3].modulate[2] = 255;	
    805 		verts[3].modulate[3] = 255;	
    806 	}
    807 	// done.
    808 	
    809 	if (!p->pshader) {
    810 // (SA) temp commented out for DM
    811 //		CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
    812 		return;
    813 	}
    814 
    815 	if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
    816 		trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
    817 	else
    818 		trap_R_AddPolyToScene( p->pshader, 4, verts );
    819 
    820 }
    821 
    822 // Ridah, made this static so it doesn't interfere with other files
    823 static float roll = 0.0;
    824 
    825 /*
    826 ===============
    827 CG_AddParticles
    828 ===============
    829 */
    830 void CG_AddParticles (void)
    831 {
    832 	cparticle_t		*p, *next;
    833 	float			alpha;
    834 	float			time, time2;
    835 	vec3_t			org;
    836 	int				color;
    837 	cparticle_t		*active, *tail;
    838 	int				type;
    839 	vec3_t			rotate_ang;
    840 
    841 	if (!initparticles)
    842 		CG_ClearParticles ();
    843 
    844 	VectorCopy( cg.refdef.viewaxis[0], vforward );
    845 	VectorCopy( cg.refdef.viewaxis[1], vright );
    846 	VectorCopy( cg.refdef.viewaxis[2], vup );
    847 
    848 	vectoangles( cg.refdef.viewaxis[0], rotate_ang );
    849 	roll += ((cg.time - oldtime) * 0.1) ;
    850 	rotate_ang[ROLL] += (roll*0.9);
    851 	AngleVectors ( rotate_ang, rforward, rright, rup);
    852 	
    853 	oldtime = cg.time;
    854 
    855 	active = NULL;
    856 	tail = NULL;
    857 
    858 	for (p=active_particles ; p ; p=next)
    859 	{
    860 
    861 		next = p->next;
    862 
    863 		time = (cg.time - p->time)*0.001;
    864 
    865 		alpha = p->alpha + time*p->alphavel;
    866 		if (alpha <= 0)
    867 		{	// faded out
    868 			p->next = free_particles;
    869 			free_particles = p;
    870 			p->type = 0;
    871 			p->color = 0;
    872 			p->alpha = 0;
    873 			continue;
    874 		}
    875 
    876 		if (p->type == P_SMOKE || p->type == P_ANIM || p->type == P_BLEED || p->type == P_SMOKE_IMPACT)
    877 		{
    878 			if (cg.time > p->endtime)
    879 			{
    880 				p->next = free_particles;
    881 				free_particles = p;
    882 				p->type = 0;
    883 				p->color = 0;
    884 				p->alpha = 0;
    885 			
    886 				continue;
    887 			}
    888 
    889 		}
    890 
    891 		if (p->type == P_WEATHER_FLURRY)
    892 		{
    893 			if (cg.time > p->endtime)
    894 			{
    895 				p->next = free_particles;
    896 				free_particles = p;
    897 				p->type = 0;
    898 				p->color = 0;
    899 				p->alpha = 0;
    900 			
    901 				continue;
    902 			}
    903 		}
    904 
    905 
    906 		if (p->type == P_FLAT_SCALEUP_FADE)
    907 		{
    908 			if (cg.time > p->endtime)
    909 			{
    910 				p->next = free_particles;
    911 				free_particles = p;
    912 				p->type = 0;
    913 				p->color = 0;
    914 				p->alpha = 0;
    915 				continue;
    916 			}
    917 
    918 		}
    919 
    920 		if ((p->type == P_BAT || p->type == P_SPRITE) && p->endtime < 0) {
    921 			// temporary sprite
    922 			CG_AddParticleToScene (p, p->org, alpha);
    923 			p->next = free_particles;
    924 			free_particles = p;
    925 			p->type = 0;
    926 			p->color = 0;
    927 			p->alpha = 0;
    928 			continue;
    929 		}
    930 
    931 		p->next = NULL;
    932 		if (!tail)
    933 			active = tail = p;
    934 		else
    935 		{
    936 			tail->next = p;
    937 			tail = p;
    938 		}
    939 
    940 		if (alpha > 1.0)
    941 			alpha = 1;
    942 
    943 		color = p->color;
    944 
    945 		time2 = time*time;
    946 
    947 		org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
    948 		org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
    949 		org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
    950 
    951 		type = p->type;
    952 
    953 		CG_AddParticleToScene (p, org, alpha);
    954 	}
    955 
    956 	active_particles = active;
    957 }
    958 
    959 /*
    960 ======================
    961 CG_AddParticles
    962 ======================
    963 */
    964 void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent)
    965 {
    966 	cparticle_t	*p;
    967 	qboolean turb = qtrue;
    968 
    969 	if (!pshader)
    970 		CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n");
    971 
    972 	if (!free_particles)
    973 		return;
    974 	p = free_particles;
    975 	free_particles = p->next;
    976 	p->next = active_particles;
    977 	active_particles = p;
    978 	p->time = cg.time;
    979 	p->color = 0;
    980 	p->alpha = 0.90f;
    981 	p->alphavel = 0;
    982 
    983 	p->start = cent->currentState.origin2[0];
    984 	p->end = cent->currentState.origin2[1];
    985 	
    986 	p->endtime = cg.time + cent->currentState.time;
    987 	p->startfade = cg.time + cent->currentState.time2;
    988 	
    989 	p->pshader = pshader;
    990 	
    991 	if (rand()%100 > 90)
    992 	{
    993 		p->height = 32;
    994 		p->width = 32;
    995 		p->alpha = 0.10f;
    996 	}
    997 	else
    998 	{
    999 		p->height = 1;
   1000 		p->width = 1;
   1001 	}
   1002 
   1003 	p->vel[2] = -20;
   1004 
   1005 	p->type = P_WEATHER_FLURRY;
   1006 	
   1007 	if (turb)
   1008 		p->vel[2] = -10;
   1009 	
   1010 	VectorCopy(cent->currentState.origin, p->org);
   1011 
   1012 	p->org[0] = p->org[0];
   1013 	p->org[1] = p->org[1];
   1014 	p->org[2] = p->org[2];
   1015 
   1016 	p->vel[0] = p->vel[1] = 0;
   1017 	
   1018 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1019 
   1020 	p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16);
   1021 	p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16);
   1022 	p->vel[2] += cent->currentState.angles[2];
   1023 
   1024 	if (turb)
   1025 	{
   1026 		p->accel[0] = crandom () * 16;
   1027 		p->accel[1] = crandom () * 16;
   1028 	}
   1029 
   1030 }
   1031 
   1032 void CG_ParticleSnow (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
   1033 {
   1034 	cparticle_t	*p;
   1035 
   1036 	if (!pshader)
   1037 		CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
   1038 
   1039 	if (!free_particles)
   1040 		return;
   1041 	p = free_particles;
   1042 	free_particles = p->next;
   1043 	p->next = active_particles;
   1044 	active_particles = p;
   1045 	p->time = cg.time;
   1046 	p->color = 0;
   1047 	p->alpha = 0.40f;
   1048 	p->alphavel = 0;
   1049 	p->start = origin[2];
   1050 	p->end = origin2[2];
   1051 	p->pshader = pshader;
   1052 	p->height = 1;
   1053 	p->width = 1;
   1054 	
   1055 	p->vel[2] = -50;
   1056 
   1057 	if (turb)
   1058 	{
   1059 		p->type = P_WEATHER_TURBULENT;
   1060 		p->vel[2] = -50 * 1.3;
   1061 	}
   1062 	else
   1063 	{
   1064 		p->type = P_WEATHER;
   1065 	}
   1066 	
   1067 	VectorCopy(origin, p->org);
   1068 
   1069 	p->org[0] = p->org[0] + ( crandom() * range);
   1070 	p->org[1] = p->org[1] + ( crandom() * range);
   1071 	p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); 
   1072 
   1073 	p->vel[0] = p->vel[1] = 0;
   1074 	
   1075 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1076 
   1077 	if (turb)
   1078 	{
   1079 		p->vel[0] = crandom() * 16;
   1080 		p->vel[1] = crandom() * 16;
   1081 	}
   1082 
   1083 	// Rafael snow pvs check
   1084 	p->snum = snum;
   1085 	p->link = qtrue;
   1086 
   1087 }
   1088 
   1089 void CG_ParticleBubble (qhandle_t pshader, vec3_t origin, vec3_t origin2, int turb, float range, int snum)
   1090 {
   1091 	cparticle_t	*p;
   1092 	float		randsize;
   1093 
   1094 	if (!pshader)
   1095 		CG_Printf ("CG_ParticleSnow pshader == ZERO!\n");
   1096 
   1097 	if (!free_particles)
   1098 		return;
   1099 	p = free_particles;
   1100 	free_particles = p->next;
   1101 	p->next = active_particles;
   1102 	active_particles = p;
   1103 	p->time = cg.time;
   1104 	p->color = 0;
   1105 	p->alpha = 0.40f;
   1106 	p->alphavel = 0;
   1107 	p->start = origin[2];
   1108 	p->end = origin2[2];
   1109 	p->pshader = pshader;
   1110 	
   1111 	randsize = 1 + (crandom() * 0.5);
   1112 	
   1113 	p->height = randsize;
   1114 	p->width = randsize;
   1115 	
   1116 	p->vel[2] = 50 + ( crandom() * 10 );
   1117 
   1118 	if (turb)
   1119 	{
   1120 		p->type = P_BUBBLE_TURBULENT;
   1121 		p->vel[2] = 50 * 1.3;
   1122 	}
   1123 	else
   1124 	{
   1125 		p->type = P_BUBBLE;
   1126 	}
   1127 	
   1128 	VectorCopy(origin, p->org);
   1129 
   1130 	p->org[0] = p->org[0] + ( crandom() * range);
   1131 	p->org[1] = p->org[1] + ( crandom() * range);
   1132 	p->org[2] = p->org[2] + ( crandom() * (p->start - p->end)); 
   1133 
   1134 	p->vel[0] = p->vel[1] = 0;
   1135 	
   1136 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1137 
   1138 	if (turb)
   1139 	{
   1140 		p->vel[0] = crandom() * 4;
   1141 		p->vel[1] = crandom() * 4;
   1142 	}
   1143 
   1144 	// Rafael snow pvs check
   1145 	p->snum = snum;
   1146 	p->link = qtrue;
   1147 
   1148 }
   1149 
   1150 void CG_ParticleSmoke (qhandle_t pshader, centity_t *cent)
   1151 {
   1152 
   1153 	// using cent->density = enttime
   1154 	//		 cent->frame = startfade
   1155 	cparticle_t	*p;
   1156 
   1157 	if (!pshader)
   1158 		CG_Printf ("CG_ParticleSmoke == ZERO!\n");
   1159 
   1160 	if (!free_particles)
   1161 		return;
   1162 	p = free_particles;
   1163 	free_particles = p->next;
   1164 	p->next = active_particles;
   1165 	active_particles = p;
   1166 	p->time = cg.time;
   1167 	
   1168 	p->endtime = cg.time + cent->currentState.time;
   1169 	p->startfade = cg.time + cent->currentState.time2;
   1170 	
   1171 	p->color = 0;
   1172 	p->alpha = 1.0;
   1173 	p->alphavel = 0;
   1174 	p->start = cent->currentState.origin[2];
   1175 	p->end = cent->currentState.origin2[2];
   1176 	p->pshader = pshader;
   1177 	p->rotate = qfalse;
   1178 	p->height = 8;
   1179 	p->width = 8;
   1180 	p->endheight = 32;
   1181 	p->endwidth = 32;
   1182 	p->type = P_SMOKE;
   1183 	
   1184 	VectorCopy(cent->currentState.origin, p->org);
   1185 
   1186 	p->vel[0] = p->vel[1] = 0;
   1187 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1188 
   1189 	p->vel[2] = 5;
   1190 
   1191 	if (cent->currentState.frame == 1)// reverse gravity	
   1192 		p->vel[2] *= -1;
   1193 
   1194 	p->roll = 8 + (crandom() * 4);
   1195 }
   1196 
   1197 
   1198 void CG_ParticleBulletDebris (vec3_t org, vec3_t vel, int duration)
   1199 {
   1200 
   1201 	cparticle_t	*p;
   1202 
   1203 	if (!free_particles)
   1204 		return;
   1205 	p = free_particles;
   1206 	free_particles = p->next;
   1207 	p->next = active_particles;
   1208 	active_particles = p;
   1209 	p->time = cg.time;
   1210 	
   1211 	p->endtime = cg.time + duration;
   1212 	p->startfade = cg.time + duration/2;
   1213 	
   1214 	p->color = EMISIVEFADE;
   1215 	p->alpha = 1.0;
   1216 	p->alphavel = 0;
   1217 
   1218 	p->height = 0.5;
   1219 	p->width = 0.5;
   1220 	p->endheight = 0.5;
   1221 	p->endwidth = 0.5;
   1222 
   1223 	p->pshader = cgs.media.tracerShader;
   1224 
   1225 	p->type = P_SMOKE;
   1226 	
   1227 	VectorCopy(org, p->org);
   1228 
   1229 	p->vel[0] = vel[0];
   1230 	p->vel[1] = vel[1];
   1231 	p->vel[2] = vel[2];
   1232 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1233 
   1234 	p->accel[2] = -60;
   1235 	p->vel[2] += -20;
   1236 	
   1237 }
   1238 
   1239 /*
   1240 ======================
   1241 CG_ParticleExplosion
   1242 ======================
   1243 */
   1244 
   1245 void CG_ParticleExplosion (char *animStr, vec3_t origin, vec3_t vel, int duration, int sizeStart, int sizeEnd)
   1246 {
   1247 	cparticle_t	*p;
   1248 	int anim;
   1249 
   1250 	if (animStr < (char *)10)
   1251 		CG_Error( "CG_ParticleExplosion: animStr is probably an index rather than a string" );
   1252 
   1253 	// find the animation string
   1254 	for (anim=0; shaderAnimNames[anim]; anim++) {
   1255 		if (!stricmp( animStr, shaderAnimNames[anim] ))
   1256 			break;
   1257 	}
   1258 	if (!shaderAnimNames[anim]) {
   1259 		CG_Error("CG_ParticleExplosion: unknown animation string: %s\n", animStr);
   1260 		return;
   1261 	}
   1262 
   1263 	if (!free_particles)
   1264 		return;
   1265 	p = free_particles;
   1266 	free_particles = p->next;
   1267 	p->next = active_particles;
   1268 	active_particles = p;
   1269 	p->time = cg.time;
   1270 	p->alpha = 1.0;
   1271 	p->alphavel = 0;
   1272 
   1273 	if (duration < 0) {
   1274 		duration *= -1;
   1275 		p->roll = 0;
   1276 	} else {
   1277 		p->roll = crandom()*179;
   1278 	}
   1279 
   1280 	p->shaderAnim = anim;
   1281 
   1282 	p->width = sizeStart;
   1283 	p->height = sizeStart*shaderAnimSTRatio[anim];	// for sprites that are stretch in either direction
   1284 
   1285 	p->endheight = sizeEnd;
   1286 	p->endwidth = sizeEnd*shaderAnimSTRatio[anim];
   1287 
   1288 	p->endtime = cg.time + duration;
   1289 
   1290 	p->type = P_ANIM;
   1291 
   1292 	VectorCopy( origin, p->org );
   1293 	VectorCopy( vel, p->vel );
   1294 	VectorClear( p->accel );
   1295 
   1296 }
   1297 
   1298 // Rafael Shrapnel
   1299 void CG_AddParticleShrapnel (localEntity_t *le)
   1300 {
   1301 	return;
   1302 }
   1303 // done.
   1304 
   1305 int CG_NewParticleArea (int num)
   1306 {
   1307 	// const char *str;
   1308 	char *str;
   1309 	char *token;
   1310 	int type;
   1311 	vec3_t origin, origin2;
   1312 	int		i;
   1313 	float range = 0;
   1314 	int turb;
   1315 	int	numparticles;
   1316 	int	snum;
   1317 	
   1318 	str = (char *) CG_ConfigString (num);
   1319 	if (!str[0])
   1320 		return (0);
   1321 	
   1322 	// returns type 128 64 or 32
   1323 	token = COM_Parse (&str);
   1324 	type = atoi (token);
   1325 	
   1326 	if (type == 1)
   1327 		range = 128;
   1328 	else if (type == 2)
   1329 		range = 64;
   1330 	else if (type == 3)
   1331 		range = 32;
   1332 	else if (type == 0)
   1333 		range = 256;
   1334 	else if (type == 4)
   1335 		range = 8;
   1336 	else if (type == 5)
   1337 		range = 16;
   1338 	else if (type == 6)
   1339 		range = 32;
   1340 	else if (type == 7)
   1341 		range = 64;
   1342 
   1343 
   1344 	for (i=0; i<3; i++)
   1345 	{
   1346 		token = COM_Parse (&str);
   1347 		origin[i] = atof (token);
   1348 	}
   1349 
   1350 	for (i=0; i<3; i++)
   1351 	{
   1352 		token = COM_Parse (&str);
   1353 		origin2[i] = atof (token);
   1354 	}
   1355 		
   1356 	token = COM_Parse (&str);
   1357 	numparticles = atoi (token);
   1358 	
   1359 	token = COM_Parse (&str);
   1360 	turb = atoi (token);
   1361 
   1362 	token = COM_Parse (&str);
   1363 	snum = atoi (token);
   1364 	
   1365 	for (i=0; i<numparticles; i++)
   1366 	{
   1367 		if (type >= 4)
   1368 			CG_ParticleBubble (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
   1369 		else
   1370 			CG_ParticleSnow (cgs.media.waterBubbleShader, origin, origin2, turb, range, snum);
   1371 	}
   1372 
   1373 	return (1);
   1374 }
   1375 
   1376 void	CG_SnowLink (centity_t *cent, qboolean particleOn)
   1377 {
   1378 	cparticle_t		*p, *next;
   1379 	int id;
   1380 
   1381 	id = cent->currentState.frame;
   1382 
   1383 	for (p=active_particles ; p ; p=next)
   1384 	{
   1385 		next = p->next;
   1386 		
   1387 		if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT)
   1388 		{
   1389 			if (p->snum == id)
   1390 			{
   1391 				if (particleOn)
   1392 					p->link = qtrue;
   1393 				else
   1394 					p->link = qfalse;
   1395 			}
   1396 		}
   1397 
   1398 	}
   1399 }
   1400 
   1401 void CG_ParticleImpactSmokePuff (qhandle_t pshader, vec3_t origin)
   1402 {
   1403 	cparticle_t	*p;
   1404 
   1405 	if (!pshader)
   1406 		CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
   1407 
   1408 	if (!free_particles)
   1409 		return;
   1410 	p = free_particles;
   1411 	free_particles = p->next;
   1412 	p->next = active_particles;
   1413 	active_particles = p;
   1414 	p->time = cg.time;
   1415 	p->alpha = 0.25;
   1416 	p->alphavel = 0;
   1417 	p->roll = crandom()*179;
   1418 
   1419 	p->pshader = pshader;
   1420 
   1421 	p->endtime = cg.time + 1000;
   1422 	p->startfade = cg.time + 100;
   1423 
   1424 	p->width = rand()%4 + 8;
   1425 	p->height = rand()%4 + 8;
   1426 
   1427 	p->endheight = p->height *2;
   1428 	p->endwidth = p->width * 2;
   1429 
   1430 	p->endtime = cg.time + 500;
   1431 
   1432 	p->type = P_SMOKE_IMPACT;
   1433 
   1434 	VectorCopy( origin, p->org );
   1435 	VectorSet(p->vel, 0, 0, 20);
   1436 	VectorSet(p->accel, 0, 0, 20);
   1437 
   1438 	p->rotate = qtrue;
   1439 }
   1440 
   1441 void CG_Particle_Bleed (qhandle_t pshader, vec3_t start, vec3_t dir, int fleshEntityNum, int duration)
   1442 {
   1443 	cparticle_t	*p;
   1444 
   1445 	if (!pshader)
   1446 		CG_Printf ("CG_Particle_Bleed pshader == ZERO!\n");
   1447 
   1448 	if (!free_particles)
   1449 		return;
   1450 	p = free_particles;
   1451 	free_particles = p->next;
   1452 	p->next = active_particles;
   1453 	active_particles = p;
   1454 	p->time = cg.time;
   1455 	p->alpha = 1.0;
   1456 	p->alphavel = 0;
   1457 	p->roll = 0;
   1458 
   1459 	p->pshader = pshader;
   1460 
   1461 	p->endtime = cg.time + duration;
   1462 	
   1463 	if (fleshEntityNum)
   1464 		p->startfade = cg.time;
   1465 	else
   1466 		p->startfade = cg.time + 100;
   1467 
   1468 	p->width = 4;
   1469 	p->height = 4;
   1470 
   1471 	p->endheight = 4+rand()%3;
   1472 	p->endwidth = p->endheight;
   1473 
   1474 	p->type = P_SMOKE;
   1475 
   1476 	VectorCopy( start, p->org );
   1477 	p->vel[0] = 0;
   1478 	p->vel[1] = 0;
   1479 	p->vel[2] = -20;
   1480 	VectorClear( p->accel );
   1481 
   1482 	p->rotate = qfalse;
   1483 
   1484 	p->roll = rand()%179;
   1485 	
   1486 	p->color = BLOODRED;
   1487 	p->alpha = 0.75;
   1488 
   1489 }
   1490 
   1491 void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent)
   1492 {
   1493 	cparticle_t	*p;
   1494 
   1495 	int			time;
   1496 	int			time2;
   1497 	float		ratio;
   1498 
   1499 	float	duration = 1500;
   1500 
   1501 	time = cg.time;
   1502 	time2 = cg.time + cent->currentState.time;
   1503 
   1504 	ratio =(float)1 - ((float)time / (float)time2);
   1505 
   1506 	if (!pshader)
   1507 		CG_Printf ("CG_Particle_OilParticle == ZERO!\n");
   1508 
   1509 	if (!free_particles)
   1510 		return;
   1511 	p = free_particles;
   1512 	free_particles = p->next;
   1513 	p->next = active_particles;
   1514 	active_particles = p;
   1515 	p->time = cg.time;
   1516 	p->alpha = 1.0;
   1517 	p->alphavel = 0;
   1518 	p->roll = 0;
   1519 
   1520 	p->pshader = pshader;
   1521 
   1522 	p->endtime = cg.time + duration;
   1523 	
   1524 	p->startfade = p->endtime;
   1525 
   1526 	p->width = 1;
   1527 	p->height = 3;
   1528 
   1529 	p->endheight = 3;
   1530 	p->endwidth = 1;
   1531 
   1532 	p->type = P_SMOKE;
   1533 
   1534 	VectorCopy(cent->currentState.origin, p->org );	
   1535 	
   1536 	p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio));
   1537 	p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio));
   1538 	p->vel[2] = (cent->currentState.origin2[2]);
   1539 
   1540 	p->snum = 1.0f;
   1541 
   1542 	VectorClear( p->accel );
   1543 
   1544 	p->accel[2] = -20;
   1545 
   1546 	p->rotate = qfalse;
   1547 
   1548 	p->roll = rand()%179;
   1549 	
   1550 	p->alpha = 0.75;
   1551 
   1552 }
   1553 
   1554 
   1555 void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent)
   1556 {
   1557 	cparticle_t	*p;
   1558 	
   1559   	if (!pshader)
   1560 		CG_Printf ("CG_Particle_OilSlick == ZERO!\n");
   1561 
   1562 	if (!free_particles)
   1563 		return;
   1564 	p = free_particles;
   1565 	free_particles = p->next;
   1566 	p->next = active_particles;
   1567 	active_particles = p;
   1568 	p->time = cg.time;
   1569 	
   1570 	if (cent->currentState.angles2[2])
   1571 		p->endtime = cg.time + cent->currentState.angles2[2];
   1572 	else
   1573 		p->endtime = cg.time + 60000;
   1574 
   1575 	p->startfade = p->endtime;
   1576 
   1577 	p->alpha = 1.0;
   1578 	p->alphavel = 0;
   1579 	p->roll = 0;
   1580 
   1581 	p->pshader = pshader;
   1582 
   1583 	if (cent->currentState.angles2[0] || cent->currentState.angles2[1])
   1584 	{
   1585 		p->width = cent->currentState.angles2[0];
   1586 		p->height = cent->currentState.angles2[0];
   1587 
   1588 		p->endheight = cent->currentState.angles2[1];
   1589 		p->endwidth = cent->currentState.angles2[1];
   1590 	}
   1591 	else
   1592 	{
   1593 		p->width = 8;
   1594 		p->height = 8;
   1595 
   1596 		p->endheight = 16;
   1597 		p->endwidth = 16;
   1598 	}
   1599 
   1600 	p->type = P_FLAT_SCALEUP;
   1601 
   1602 	p->snum = 1.0;
   1603 
   1604 	VectorCopy(cent->currentState.origin, p->org );
   1605 	
   1606 	p->org[2]+= 0.55 + (crandom() * 0.5);
   1607 
   1608 	p->vel[0] = 0;
   1609 	p->vel[1] = 0;
   1610 	p->vel[2] = 0;
   1611 	VectorClear( p->accel );
   1612 
   1613 	p->rotate = qfalse;
   1614 
   1615 	p->roll = rand()%179;
   1616 	
   1617 	p->alpha = 0.75;
   1618 
   1619 }
   1620 
   1621 void CG_OilSlickRemove (centity_t *cent)
   1622 {
   1623 	cparticle_t		*p, *next;
   1624 	int				id;
   1625 
   1626 	id = 1.0f;
   1627 
   1628 	if (!id)
   1629 		CG_Printf ("CG_OilSlickRevove NULL id\n");
   1630 
   1631 	for (p=active_particles ; p ; p=next)
   1632 	{
   1633 		next = p->next;
   1634 		
   1635 		if (p->type == P_FLAT_SCALEUP)
   1636 		{
   1637 			if (p->snum == id)
   1638 			{
   1639 				p->endtime = cg.time + 100;
   1640 				p->startfade = p->endtime;
   1641 				p->type = P_FLAT_SCALEUP_FADE;
   1642 
   1643 			}
   1644 		}
   1645 
   1646 	}
   1647 }
   1648 
   1649 qboolean ValidBloodPool (vec3_t start)
   1650 {
   1651 #define EXTRUDE_DIST	0.5
   1652 
   1653 	vec3_t	angles;
   1654 	vec3_t	right, up;
   1655 	vec3_t	this_pos, x_pos, center_pos, end_pos;
   1656 	float	x, y;
   1657 	float	fwidth, fheight;
   1658 	trace_t	trace;
   1659 	vec3_t	normal;
   1660 
   1661 	fwidth = 16;
   1662 	fheight = 16;
   1663 
   1664 	VectorSet (normal, 0, 0, 1);
   1665 
   1666 	vectoangles (normal, angles);
   1667 	AngleVectors (angles, NULL, right, up);
   1668 
   1669 	VectorMA (start, EXTRUDE_DIST, normal, center_pos);
   1670 
   1671 	for (x= -fwidth/2; x<fwidth; x+= fwidth)
   1672 	{
   1673 		VectorMA (center_pos, x, right, x_pos);
   1674 
   1675 		for (y= -fheight/2; y<fheight; y+= fheight)
   1676 		{
   1677 			VectorMA (x_pos, y, up, this_pos);
   1678 			VectorMA (this_pos, -EXTRUDE_DIST*2, normal, end_pos);
   1679 			
   1680 			CG_Trace (&trace, this_pos, NULL, NULL, end_pos, -1, CONTENTS_SOLID);
   1681 
   1682 			
   1683 			if (trace.entityNum < (MAX_ENTITIES - 1)) // may only land on world
   1684 				return qfalse;
   1685 
   1686 			if (!(!trace.startsolid && trace.fraction < 1))
   1687 				return qfalse;
   1688 		
   1689 		}
   1690 	}
   1691 
   1692 	return qtrue;
   1693 }
   1694 
   1695 void CG_BloodPool (localEntity_t *le, qhandle_t pshader, trace_t *tr)
   1696 {	
   1697 	cparticle_t	*p;
   1698 	qboolean	legit;
   1699 	vec3_t		start;
   1700 	float		rndSize;
   1701 	
   1702 	if (!pshader)
   1703 		CG_Printf ("CG_BloodPool pshader == ZERO!\n");
   1704 
   1705 	if (!free_particles)
   1706 		return;
   1707 	
   1708 	VectorCopy (tr->endpos, start);
   1709 	legit = ValidBloodPool (start);
   1710 
   1711 	if (!legit) 
   1712 		return;
   1713 
   1714 	p = free_particles;
   1715 	free_particles = p->next;
   1716 	p->next = active_particles;
   1717 	active_particles = p;
   1718 	p->time = cg.time;
   1719 	
   1720 	p->endtime = cg.time + 3000;
   1721 	p->startfade = p->endtime;
   1722 
   1723 	p->alpha = 1.0;
   1724 	p->alphavel = 0;
   1725 	p->roll = 0;
   1726 
   1727 	p->pshader = pshader;
   1728 
   1729 	rndSize = 0.4 + random()*0.6;
   1730 
   1731 	p->width = 8*rndSize;
   1732 	p->height = 8*rndSize;
   1733 
   1734 	p->endheight = 16*rndSize;
   1735 	p->endwidth = 16*rndSize;
   1736 	
   1737 	p->type = P_FLAT_SCALEUP;
   1738 
   1739 	VectorCopy(start, p->org );
   1740 	
   1741 	p->vel[0] = 0;
   1742 	p->vel[1] = 0;
   1743 	p->vel[2] = 0;
   1744 	VectorClear( p->accel );
   1745 
   1746 	p->rotate = qfalse;
   1747 
   1748 	p->roll = rand()%179;
   1749 	
   1750 	p->alpha = 0.75;
   1751 	
   1752 	p->color = BLOODRED;
   1753 }
   1754 
   1755 #define NORMALSIZE	16
   1756 #define LARGESIZE	32
   1757 
   1758 void CG_ParticleBloodCloud (centity_t *cent, vec3_t origin, vec3_t dir)
   1759 {
   1760 	float	length;
   1761 	float	dist;
   1762 	float	crittersize;
   1763 	vec3_t	angles, forward;
   1764 	vec3_t	point;
   1765 	cparticle_t	*p;
   1766 	int		i;
   1767 	
   1768 	dist = 0;
   1769 
   1770 	length = VectorLength (dir);
   1771 	vectoangles (dir, angles);
   1772 	AngleVectors (angles, forward, NULL, NULL);
   1773 
   1774 	crittersize = LARGESIZE;
   1775 
   1776 	if (length)
   1777 		dist = length / crittersize;
   1778 
   1779 	if (dist < 1)
   1780 		dist = 1;
   1781 
   1782 	VectorCopy (origin, point);
   1783 
   1784 	for (i=0; i<dist; i++)
   1785 	{
   1786 		VectorMA (point, crittersize, forward, point);	
   1787 		
   1788 		if (!free_particles)
   1789 			return;
   1790 
   1791 		p = free_particles;
   1792 		free_particles = p->next;
   1793 		p->next = active_particles;
   1794 		active_particles = p;
   1795 
   1796 		p->time = cg.time;
   1797 		p->alpha = 1.0;
   1798 		p->alphavel = 0;
   1799 		p->roll = 0;
   1800 
   1801 		p->pshader = cgs.media.smokePuffShader;
   1802 
   1803 		p->endtime = cg.time + 350 + (crandom() * 100);
   1804 		
   1805 		p->startfade = cg.time;
   1806 		
   1807 		p->width = LARGESIZE;
   1808 		p->height = LARGESIZE;
   1809 		p->endheight = LARGESIZE;
   1810 		p->endwidth = LARGESIZE;
   1811 
   1812 		p->type = P_SMOKE;
   1813 
   1814 		VectorCopy( origin, p->org );
   1815 		
   1816 		p->vel[0] = 0;
   1817 		p->vel[1] = 0;
   1818 		p->vel[2] = -1;
   1819 		
   1820 		VectorClear( p->accel );
   1821 
   1822 		p->rotate = qfalse;
   1823 
   1824 		p->roll = rand()%179;
   1825 		
   1826 		p->color = BLOODRED;
   1827 		
   1828 		p->alpha = 0.75;
   1829 		
   1830 	}
   1831 
   1832 	
   1833 }
   1834 
   1835 void CG_ParticleSparks (vec3_t org, vec3_t vel, int duration, float x, float y, float speed)
   1836 {
   1837 	cparticle_t	*p;
   1838 
   1839 	if (!free_particles)
   1840 		return;
   1841 	p = free_particles;
   1842 	free_particles = p->next;
   1843 	p->next = active_particles;
   1844 	active_particles = p;
   1845 	p->time = cg.time;
   1846 	
   1847 	p->endtime = cg.time + duration;
   1848 	p->startfade = cg.time + duration/2;
   1849 	
   1850 	p->color = EMISIVEFADE;
   1851 	p->alpha = 0.4f;
   1852 	p->alphavel = 0;
   1853 
   1854 	p->height = 0.5;
   1855 	p->width = 0.5;
   1856 	p->endheight = 0.5;
   1857 	p->endwidth = 0.5;
   1858 
   1859 	p->pshader = cgs.media.tracerShader;
   1860 
   1861 	p->type = P_SMOKE;
   1862 	
   1863 	VectorCopy(org, p->org);
   1864 
   1865 	p->org[0] += (crandom() * x);
   1866 	p->org[1] += (crandom() * y);
   1867 
   1868 	p->vel[0] = vel[0];
   1869 	p->vel[1] = vel[1];
   1870 	p->vel[2] = vel[2];
   1871 
   1872 	p->accel[0] = p->accel[1] = p->accel[2] = 0;
   1873 
   1874 	p->vel[0] += (crandom() * 4);
   1875 	p->vel[1] += (crandom() * 4);
   1876 	p->vel[2] += (20 + (crandom() * 10)) * speed;	
   1877 
   1878 	p->accel[0] = crandom () * 4;
   1879 	p->accel[1] = crandom () * 4;
   1880 	
   1881 }
   1882 
   1883 void CG_ParticleDust (centity_t *cent, vec3_t origin, vec3_t dir)
   1884 {
   1885 	float	length;
   1886 	float	dist;
   1887 	float	crittersize;
   1888 	vec3_t	angles, forward;
   1889 	vec3_t	point;
   1890 	cparticle_t	*p;
   1891 	int		i;
   1892 	
   1893 	dist = 0;
   1894 
   1895 	VectorNegate (dir, dir);
   1896 	length = VectorLength (dir);
   1897 	vectoangles (dir, angles);
   1898 	AngleVectors (angles, forward, NULL, NULL);
   1899 
   1900 	crittersize = LARGESIZE;
   1901 
   1902 	if (length)
   1903 		dist = length / crittersize;
   1904 
   1905 	if (dist < 1)
   1906 		dist = 1;
   1907 
   1908 	VectorCopy (origin, point);
   1909 
   1910 	for (i=0; i<dist; i++)
   1911 	{
   1912 		VectorMA (point, crittersize, forward, point);	
   1913 				
   1914 		if (!free_particles)
   1915 			return;
   1916 
   1917 		p = free_particles;
   1918 		free_particles = p->next;
   1919 		p->next = active_particles;
   1920 		active_particles = p;
   1921 
   1922 		p->time = cg.time;
   1923 		p->alpha = 5.0;
   1924 		p->alphavel = 0;
   1925 		p->roll = 0;
   1926 
   1927 		p->pshader = cgs.media.smokePuffShader;
   1928 
   1929 		// RF, stay around for long enough to expand and dissipate naturally
   1930 		if (length)
   1931 			p->endtime = cg.time + 4500 + (crandom() * 3500);
   1932 		else
   1933 			p->endtime = cg.time + 750 + (crandom() * 500);
   1934 		
   1935 		p->startfade = cg.time;
   1936 		
   1937 		p->width = LARGESIZE;
   1938 		p->height = LARGESIZE;
   1939 
   1940 		// RF, expand while falling
   1941 		p->endheight = LARGESIZE*3.0;
   1942 		p->endwidth = LARGESIZE*3.0;
   1943 
   1944 		if (!length)
   1945 		{
   1946 			p->width *= 0.2f;
   1947 			p->height *= 0.2f;
   1948 
   1949 			p->endheight = NORMALSIZE;
   1950 			p->endwidth = NORMALSIZE;
   1951 		}
   1952 
   1953 		p->type = P_SMOKE;
   1954 
   1955 		VectorCopy( point, p->org );
   1956 		
   1957 		p->vel[0] = crandom()*6;
   1958 		p->vel[1] = crandom()*6;
   1959 		p->vel[2] = random()*20;
   1960 
   1961 		// RF, add some gravity/randomness
   1962 		p->accel[0] = crandom()*3;
   1963 		p->accel[1] = crandom()*3;
   1964 		p->accel[2] = -PARTICLE_GRAVITY*0.4;
   1965 
   1966 		VectorClear( p->accel );
   1967 
   1968 		p->rotate = qfalse;
   1969 
   1970 		p->roll = rand()%179;
   1971 		
   1972 		p->alpha = 0.75;
   1973 		
   1974 	}
   1975 
   1976 	
   1977 }
   1978 
   1979 void CG_ParticleMisc (qhandle_t pshader, vec3_t origin, int size, int duration, float alpha)
   1980 {
   1981 	cparticle_t	*p;
   1982 
   1983 	if (!pshader)
   1984 		CG_Printf ("CG_ParticleImpactSmokePuff pshader == ZERO!\n");
   1985 
   1986 	if (!free_particles)
   1987 		return;
   1988 
   1989 	p = free_particles;
   1990 	free_particles = p->next;
   1991 	p->next = active_particles;
   1992 	active_particles = p;
   1993 	p->time = cg.time;
   1994 	p->alpha = 1.0;
   1995 	p->alphavel = 0;
   1996 	p->roll = rand()%179;
   1997 
   1998 	p->pshader = pshader;
   1999 
   2000 	if (duration > 0)
   2001 		p->endtime = cg.time + duration;
   2002 	else
   2003 		p->endtime = duration;
   2004 
   2005 	p->startfade = cg.time;
   2006 
   2007 	p->width = size;
   2008 	p->height = size;
   2009 
   2010 	p->endheight = size;
   2011 	p->endwidth = size;
   2012 
   2013 	p->type = P_SPRITE;
   2014 
   2015 	VectorCopy( origin, p->org );
   2016 
   2017 	p->rotate = qfalse;
   2018 }