misc. cleanup, bubble trails fixed, improved lightmap compatibility.
[xonotic/darkplaces.git] / r_part.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 #define MAX_PARTICLES                   4096    // default max # of particles at one
24                                                                                 //  time
25 #define ABSOLUTE_MIN_PARTICLES  512             // no fewer than this no matter what's
26                                                                                 //  on the command line
27
28 int             ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
29 int             ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
30 int             ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
31
32 int             particletexture;
33 int             smokeparticletexture;
34 int             flareparticletexture;
35 int             rainparticletexture;
36 int             bloodcloudparticletexture;
37 int             bubbleparticletexture;
38
39 particle_t      *active_particles, *free_particles;
40
41 particle_t      *particles;
42 int                     r_numparticles;
43
44 vec3_t                  r_pright, r_pup, r_ppn;
45
46 cvar_t r_particles = {"r_particles", "1", true};
47
48 void fractalnoise(char *noise, int size);
49 void fractalnoise_zeroedge(char *noise, int size);
50
51 void R_InitParticleTexture (void)
52 {
53         int             x,y,d;
54         float   dx, dy, dz, f, dot;
55         byte    data[32][32][4], noise1[32][32], noise2[32][32];
56         vec3_t  normal, light;
57
58         particletexture = texture_extension_number++;
59     glBindTexture(GL_TEXTURE_2D, particletexture);
60
61         for (x=0 ; x<32 ; x++)
62         {
63                 for (y=0 ; y<32 ; y++)
64                 {
65                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
66                         dx = x - 16;
67                         dy = y - 16;
68                         d = (255 - (dx*dx+dy*dy));
69                         if (d < 0) d = 0;
70                         data[y][x][3] = (byte) d;
71                 }
72         }
73         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
74
75         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
76
77         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
79
80
81         fractalnoise(&noise1[0][0], 32);
82         fractalnoise(&noise2[0][0], 32);
83         for (y = 0;y < 32;y++)
84                 for (x = 0;x < 32;x++)
85                 {
86                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
87                         dx = x - 16;
88                         dy = y - 16;
89                         d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f);
90                         if (d < 0) d = 0;
91                         if (d > 255) d = 255;
92                         data[y][x][3] = (byte) d;
93                 }
94
95         /*
96         for (x=0 ; x<34 ; x+=2)
97                 for (y=0 ; y<34 ; y+=2)
98                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%32)+192;
99         for (x=0 ; x<32 ; x+=2)
100                 for (y=0 ; y<32 ; y+=2)
101                 {
102                         data[y  ][x+1][0] = data[y  ][x+1][1] = data[y  ][x+1][2] = (int) (data[y  ][x  ][0] + data[y  ][x+2][0]) >> 1;
103                         data[y+1][x  ][0] = data[y+1][x  ][1] = data[y+1][x  ][2] = (int) (data[y  ][x  ][0] + data[y+2][x  ][0]) >> 1;
104                         data[y+1][x+1][0] = data[y+1][x+1][1] = data[y+1][x+1][2] = (int) (data[y  ][x  ][0] + data[y  ][x+2][0] + data[y+2][x  ][0] + data[y+2][x+2][0]) >> 2;
105                 }
106         for (x=0 ; x<32 ; x++)
107         {
108                 for (y=0 ; y<32 ; y++)
109                 {
110                         //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+32;
111                         dx = x - 16;
112                         dy = y - 16;
113                         d = (255 - (dx*dx+dy*dy));
114                         if (d < 0) d = 0;
115                         data[y][x][3] = (byte) d;
116                 }
117         }
118         */
119         smokeparticletexture = texture_extension_number++;
120         glBindTexture(GL_TEXTURE_2D, smokeparticletexture);
121         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
122         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
123         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
124         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
125
126         fractalnoise(&noise1[0][0], 32);
127         fractalnoise(&noise2[0][0], 32);
128         for (y = 0;y < 32;y++)
129                 for (x = 0;x < 32;x++)
130                 {
131                         data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
132                         dx = x - 16;
133                         dy = y - 16;
134                         d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f);
135                         if (d < 0) d = 0;
136                         if (d > 255) d = 255;
137                         data[y][x][3] = (byte) d;
138                 }
139
140         bloodcloudparticletexture = texture_extension_number++;
141         glBindTexture(GL_TEXTURE_2D, bloodcloudparticletexture);
142         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
143         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
144         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
145         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
146
147         flareparticletexture = texture_extension_number++;
148     glBindTexture(GL_TEXTURE_2D, flareparticletexture);
149
150         for (x=0 ; x<32 ; x++)
151         {
152                 for (y=0 ; y<32 ; y++)
153                 {
154                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
155                         dx = x - 16;
156                         dy = y - 16;
157                         d = 2048 / (dx*dx+dy*dy+1) - 32;
158                         d = bound(0, d, 255);
159                         data[y][x][3] = (byte) d;
160                 }
161         }
162         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
163
164         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
165
166         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
167         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
168
169         rainparticletexture = texture_extension_number++;
170     glBindTexture(GL_TEXTURE_2D, rainparticletexture);
171
172         for (x=0 ; x<32 ; x++)
173         {
174                 for (y=0 ; y<32 ; y++)
175                 {
176                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
177                         if (y < 24) // stretch the upper half to make a raindrop
178                         {
179                                 dx = (x - 16)*2;
180                                 dy = (y - 24)*2/3;
181                                 d = (255 - (dx*dx+dy*dy))/2;
182                         }
183                         else
184                         {
185                                 dx = (x - 16)*2;
186                                 dy = (y - 24)*2;
187                                 d = (255 - (dx*dx+dy*dy))/2;
188                         }
189                         if (d < 0) d = 0;
190                         data[y][x][3] = (byte) d;
191                 }
192         }
193         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
194
195         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
196
197         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
198         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199
200         bubbleparticletexture = texture_extension_number++;
201     glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
202
203         light[0] = 1;light[1] = 1;light[2] = 1;
204         VectorNormalize(light);
205         for (x=0 ; x<32 ; x++)
206         {
207                 for (y=0 ; y<32 ; y++)
208                 {
209                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
210                         dx = x * (1.0 / 16.0) - 1.0;
211                         dy = y * (1.0 / 16.0) - 1.0;
212                         if (dx*dx+dy*dy < 1) // it does hit the sphere
213                         {
214                                 dz = 1 - (dx*dx+dy*dy);
215                                 f = 0;
216                                 // back side
217                                 normal[0] = dx;normal[1] = dy;normal[2] = dz;
218                                 VectorNormalize(normal);
219                                 dot = DotProduct(normal, light);
220                                 if (dot > 0.5) // interior reflection
221                                         f += ((dot *  2) - 1);
222                                 else if (dot < -0.5) // exterior reflection
223                                         f += ((dot * -2) - 1);
224                                 // front side
225                                 normal[0] = dx;normal[1] = dy;normal[2] = -dz;
226                                 VectorNormalize(normal);
227                                 dot = DotProduct(normal, light);
228                                 if (dot > 0.5) // interior reflection
229                                         f += ((dot *  2) - 1);
230                                 else if (dot < -0.5) // exterior reflection
231                                         f += ((dot * -2) - 1);
232                                 f *= 64;
233                                 f = bound(0, f, 255);
234                                 data[y][x][3] = (byte) f;
235                         }
236                         else
237                                 data[y][x][3] = 0;
238                 }
239         }
240         glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
241
242         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
243
244         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
245         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
246 }
247
248 /*
249 ===============
250 R_InitParticles
251 ===============
252 */
253 void R_InitParticles (void)
254 {
255         int             i;
256
257         i = COM_CheckParm ("-particles");
258
259         if (i)
260         {
261                 r_numparticles = (int)(atoi(com_argv[i+1]));
262                 if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
263                         r_numparticles = ABSOLUTE_MIN_PARTICLES;
264         }
265         else
266         {
267                 r_numparticles = MAX_PARTICLES;
268         }
269
270         particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
271
272         Cvar_RegisterVariable (&r_particles);
273         R_InitParticleTexture ();
274 }
275
276 /*
277 ===============
278 R_EntityParticles
279 ===============
280 */
281
282 #define NUMVERTEXNORMALS        162
283 extern  float   r_avertexnormals[NUMVERTEXNORMALS][3];
284 vec3_t  avelocities[NUMVERTEXNORMALS];
285 float   beamlength = 16;
286 vec3_t  avelocity = {23, 7, 3};
287 float   partstep = 0.01;
288 float   timescale = 0.01;
289
290 void R_EntityParticles (entity_t *ent)
291 {
292         int                     count;
293         int                     i;
294         particle_t      *p;
295         float           angle;
296         float           sr, sp, sy, cr, cp, cy;
297         vec3_t          forward;
298         float           dist;
299         if (!r_particles.value) return; // LordHavoc: particles are optional
300         
301         dist = 64;
302         count = 50;
303
304 if (!avelocities[0][0])
305 {
306 for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
307 avelocities[0][i] = (rand()&255) * 0.01;
308 }
309
310
311         for (i=0 ; i<NUMVERTEXNORMALS ; i++)
312         {
313                 angle = cl.time * avelocities[i][0];
314                 sy = sin(angle);
315                 cy = cos(angle);
316                 angle = cl.time * avelocities[i][1];
317                 sp = sin(angle);
318                 cp = cos(angle);
319                 angle = cl.time * avelocities[i][2];
320                 sr = sin(angle);
321                 cr = cos(angle);
322         
323                 forward[0] = cp*cy;
324                 forward[1] = cp*sy;
325                 forward[2] = -sp;
326
327                 if (!free_particles)
328                         return;
329                 p = free_particles;
330                 free_particles = p->next;
331                 p->next = active_particles;
332                 active_particles = p;
333
334                 p->texnum = flareparticletexture;
335                 p->scale = 2;
336                 p->alpha = 255;
337                 p->die = cl.time + 0.01;
338                 p->color = 0x6f;
339                 p->type = pt_explode;
340                 
341                 p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;                       
342                 p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;                       
343                 p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;                       
344         }
345 }
346
347
348 /*
349 ===============
350 R_ClearParticles
351 ===============
352 */
353 void R_ClearParticles (void)
354 {
355         int             i;
356         
357         free_particles = &particles[0];
358         active_particles = NULL;
359
360         for (i=0 ;i<r_numparticles ; i++)
361                 particles[i].next = &particles[i+1];
362         particles[r_numparticles-1].next = NULL;
363 }
364
365
366 void R_ReadPointFile_f (void)
367 {
368         FILE    *f;
369         vec3_t  org;
370         int             r;
371         int             c;
372         particle_t      *p;
373         char    name[MAX_OSPATH];
374         
375         sprintf (name,"maps/%s.pts", sv.name);
376
377         COM_FOpenFile (name, &f, false);
378         if (!f)
379         {
380                 Con_Printf ("couldn't open %s\n", name);
381                 return;
382         }
383         
384         Con_Printf ("Reading %s...\n", name);
385         c = 0;
386         for ( ;; )
387         {
388                 r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
389                 if (r != 3)
390                         break;
391                 c++;
392                 
393                 if (!free_particles)
394                 {
395                         Con_Printf ("Not enough free particles\n");
396                         break;
397                 }
398                 p = free_particles;
399                 free_particles = p->next;
400                 p->next = active_particles;
401                 active_particles = p;
402                 
403                 p->texnum = particletexture;
404                 p->scale = 2;
405                 p->alpha = 255;
406                 p->die = 99999;
407                 p->color = (-c)&15;
408                 p->type = pt_static;
409                 VectorCopy (vec3_origin, p->vel);
410                 VectorCopy (org, p->org);
411         }
412
413         fclose (f);
414         Con_Printf ("%i points read\n", c);
415 }
416
417 /*
418 ===============
419 R_ParseParticleEffect
420
421 Parse an effect out of the server message
422 ===============
423 */
424 void R_ParseParticleEffect (void)
425 {
426         vec3_t          org, dir;
427         int                     i, count, msgcount, color;
428         
429         for (i=0 ; i<3 ; i++)
430                 org[i] = MSG_ReadCoord ();
431         for (i=0 ; i<3 ; i++)
432                 dir[i] = MSG_ReadChar () * (1.0/16);
433         msgcount = MSG_ReadByte ();
434         color = MSG_ReadByte ();
435
436 if (msgcount == 255)
437         count = 1024;
438 else
439         count = msgcount;
440         
441         R_RunParticleEffect (org, dir, color, count);
442 }
443         
444 /*
445 ===============
446 R_ParticleExplosion
447
448 ===============
449 */
450 void R_ParticleExplosion (vec3_t org, int smoke)
451 {
452         int                     i, j;
453         particle_t      *p;
454         if (!r_particles.value) return; // LordHavoc: particles are optional
455         
456         for (i=0 ; i<1024 ; i++)
457         {
458                 if (!free_particles)
459                         return;
460                 p = free_particles;
461                 free_particles = p->next;
462                 p->next = active_particles;
463                 active_particles = p;
464
465                 p->texnum = flareparticletexture;
466                 p->scale = lhrandom(2,5);
467                 p->alpha = rand()&255;
468                 p->die = cl.time + 5;
469                 p->color = ramp1[0];
470                 p->ramp = rand()&3;
471                 /*
472                 if (i & 1)
473                         p->type = pt_explode;
474                 else
475                         p->type = pt_explode2;
476                 */
477                 p->color = ramp1[rand()&7];
478                 p->type = pt_fallfadespark;
479                 for (j=0 ; j<3 ; j++)
480                 {
481                         p->org[j] = org[j] + ((rand()&63)-32);
482                         p->vel[j] = (rand()&511)-256;
483                 }
484                 p->vel[j] += 200;
485         }
486
487         if (smoke)
488         {
489                 for (i=0 ; i<32 ; i++)
490                 {
491                         if (!free_particles)
492                                 return;
493                         p = free_particles;
494                         free_particles = p->next;
495                         p->next = active_particles;
496                         active_particles = p;
497
498                         p->texnum = smokeparticletexture;
499                         p->scale = 12;
500                         p->alpha = 80;
501                         p->die = cl.time + 2;
502                         p->type = pt_smoke;
503                         p->color = (rand()&7) + 8;
504                         for (j=0 ; j<3 ; j++)
505                         {
506                                 p->org[j] = org[j] + ((rand()%96)-48);
507                                 p->vel[j] = (rand()&63)-32;
508                         }
509                 }
510         }
511 }
512
513 /*
514 ===============
515 R_ParticleExplosion2
516
517 ===============
518 */
519 void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
520 {
521         int                     i, j;
522         particle_t      *p;
523         int                     colorMod = 0;
524         if (!r_particles.value) return; // LordHavoc: particles are optional
525
526         for (i=0; i<512; i++)
527         {
528                 if (!free_particles)
529                         return;
530                 p = free_particles;
531                 free_particles = p->next;
532                 p->next = active_particles;
533                 active_particles = p;
534
535                 p->texnum = flareparticletexture;
536                 p->scale = 4;
537                 p->alpha = 255;
538                 p->die = cl.time + 0.3;
539                 p->color = colorStart + (colorMod % colorLength);
540                 colorMod++;
541
542                 p->type = pt_blob;
543                 for (j=0 ; j<3 ; j++)
544                 {
545                         p->org[j] = org[j] + ((rand()%32)-16);
546                         p->vel[j] = (rand()%512)-256;
547                 }
548         }
549 }
550
551 /*
552 ===============
553 R_BlobExplosion
554
555 ===============
556 */
557 void R_BlobExplosion (vec3_t org)
558 {
559         int                     i, j;
560         particle_t      *p;
561         if (!r_particles.value) return; // LordHavoc: particles are optional
562         
563         for (i=0 ; i<1024 ; i++)
564         {
565                 if (!free_particles)
566                         return;
567                 p = free_particles;
568                 free_particles = p->next;
569                 p->next = active_particles;
570                 active_particles = p;
571
572                 p->texnum = flareparticletexture;
573                 p->scale = 4;
574                 p->alpha = 255;
575                 p->die = cl.time + 1 + (rand()&8)*0.05;
576
577                 if (i & 1)
578                 {
579                         p->type = pt_blob;
580                         p->color = 66 + rand()%6;
581                         for (j=0 ; j<3 ; j++)
582                         {
583                                 p->org[j] = org[j] + ((rand()%32)-16);
584                                 p->vel[j] = (rand()%512)-256;
585                         }
586                 }
587                 else
588                 {
589                         p->type = pt_blob2;
590                         p->color = 150 + rand()%6;
591                         for (j=0 ; j<3 ; j++)
592                         {
593                                 p->org[j] = org[j] + ((rand()%32)-16);
594                                 p->vel[j] = (rand()%512)-256;
595                         }
596                 }
597         }
598 }
599
600 /*
601 ===============
602 R_RunParticleEffect
603
604 ===============
605 */
606 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
607 {
608         int                     i, j;
609         particle_t      *p;
610         if (!r_particles.value) return; // LordHavoc: particles are optional
611         
612         for (i=0 ; i<count ; i++)
613         {
614                 if (!free_particles)
615                         return;
616                 p = free_particles;
617                 free_particles = p->next;
618                 p->next = active_particles;
619                 active_particles = p;
620
621                 if (count == 1024)
622                 {       // rocket explosion
623                         p->texnum = flareparticletexture;
624                         p->scale = 4;
625                         p->alpha = 255;
626                         p->die = cl.time + 5;
627                         p->color = ramp1[0];
628                         p->ramp = rand()&3;
629                         if (i & 1)
630                         {
631                                 p->type = pt_explode;
632                                 for (j=0 ; j<3 ; j++)
633                                 {
634                                         p->org[j] = org[j] + ((rand()%32)-16);
635                                         p->vel[j] = (rand()%512)-256;
636                                 }
637                         }
638                         else
639                         {
640                                 p->type = pt_explode2;
641                                 for (j=0 ; j<3 ; j++)
642                                 {
643                                         p->org[j] = org[j] + ((rand()%32)-16);
644                                         p->vel[j] = (rand()%512)-256;
645                                 }
646                         }
647                 }
648                 else
649                 {
650                         p->texnum = flareparticletexture;
651                         p->scale = 4;
652                         p->alpha = 255;
653                         p->die = cl.time + 0.1*(rand()%5);
654                         p->color = (color&~7) + (rand()&7);
655                         p->type = pt_static; //slowgrav;
656                         for (j=0 ; j<3 ; j++)
657                         {
658                                 p->org[j] = org[j] + ((rand()&15)-8);
659                                 p->vel[j] = dir[j]*15;// + (rand()%300)-150;
660                         }
661                 }
662         }
663 }
664
665 // LordHavoc: added this for spawning sparks/dust (which have strong gravity)
666 /*
667 ===============
668 R_SparkShower
669
670 ===============
671 */
672 void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
673 {
674         int                     i, j;
675         particle_t      *p;
676         if (!r_particles.value) return; // LordHavoc: particles are optional
677
678         if (!free_particles)
679                 return;
680         p = free_particles;
681         free_particles = p->next;
682         p->next = active_particles;
683         active_particles = p;
684         if (type == 0) // sparks
685         {
686                 p->texnum = smokeparticletexture;
687                 p->scale = 10;
688                 p->alpha = 64;
689                 p->color = (rand()&3)+12;
690                 p->type = pt_bulletpuff;
691                 p->die = cl.time + 1;
692                 VectorCopy(org, p->org);
693                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
694         }
695         else // blood
696         {
697                 p->texnum = bloodcloudparticletexture;
698                 p->scale = 12;
699                 p->alpha = 128;
700                 p->color = (rand()&3)+68;
701                 p->type = pt_bloodcloud;
702                 p->die = cl.time + 0.5;
703                 VectorCopy(org, p->org);
704                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
705                 return;
706         }
707         for (i=0 ; i<count ; i++)
708         {
709                 if (!free_particles)
710                         return;
711                 p = free_particles;
712                 free_particles = p->next;
713                 p->next = active_particles;
714                 active_particles = p;
715
716                 p->texnum = flareparticletexture;
717                 p->scale = 2;
718                 p->alpha = 255;
719                 p->die = cl.time + 0.0625 * (rand()&15);
720                 /*
721                 if (type == 0) // sparks
722                 {
723                 */
724                         p->type = pt_dust;
725                         p->ramp = (rand()&3);
726                         p->color = ramp1[(int)p->ramp];
727                         for (j=0 ; j<3 ; j++)
728                         {
729                                 p->org[j] = org[j] + ((rand()&7)-4);
730                                 p->vel[j] = dir[j] + (rand()%192)-96;
731                         }
732                 /*
733                 }
734                 else // blood
735                 {
736                         p->type = pt_fadespark2;
737                         p->color = 67 + (rand()&3);
738                         for (j=0 ; j<3 ; j++)
739                         {
740                                 p->org[j] = org[j] + (rand()&7)-4;
741                                 p->vel[j] = dir[j] + (rand()&63)-32;
742                         }
743                 }
744                 */
745         }
746 }
747
748 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
749 {
750         int                     i, j;
751         particle_t      *p;
752         vec3_t          diff;
753         vec3_t          center;
754         vec3_t          velscale;
755         if (!r_particles.value) return; // LordHavoc: particles are optional
756
757         VectorSubtract(maxs, mins, diff);
758         center[0] = (mins[0] + maxs[0]) * 0.5;
759         center[1] = (mins[1] + maxs[1]) * 0.5;
760         center[2] = (mins[2] + maxs[2]) * 0.5;
761         velscale[0] = velspeed * 2.0 / diff[0];
762         velscale[1] = velspeed * 2.0 / diff[1];
763         velscale[2] = velspeed * 2.0 / diff[2];
764         
765         for (i=0 ; i<count ; i++)
766         {
767                 if (!free_particles)
768                         return;
769                 p = free_particles;
770                 free_particles = p->next;
771                 p->next = active_particles;
772                 active_particles = p;
773
774                 p->texnum = bloodcloudparticletexture;
775                 p->scale = 12;
776                 p->alpha = 96 + (rand()&63);
777                 p->die = cl.time + 2; //0.015625 * (rand()%128);
778                 p->type = pt_fadespark;
779                 p->color = (rand()&3)+68;
780 //              p->color = 67 + (rand()&3);
781                 for (j=0 ; j<3 ; j++)
782                 {
783                         p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j];
784                         p->vel[j] = (p->org[j] - center[j]) * velscale[j];
785                 }
786         }
787 }
788
789 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel)
790 {
791         int                     i, j;
792         particle_t      *p;
793         vec3_t          diff;
794         float           t;
795         if (!r_particles.value) return; // LordHavoc: particles are optional
796         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
797         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
798         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
799
800         VectorSubtract(maxs, mins, diff);
801         
802         for (i=0 ; i<count ; i++)
803         {
804                 if (!free_particles)
805                         return;
806                 p = free_particles;
807                 free_particles = p->next;
808                 p->next = active_particles;
809                 active_particles = p;
810
811                 p->texnum = flareparticletexture;
812                 p->scale = 6;
813                 p->alpha = 255;
814                 p->die = cl.time + 1 + (rand()&15)*0.0625;
815                 if (gravity)
816                         p->type = pt_grav;
817                 else
818                         p->type = pt_static;
819                 p->color = colorbase + (rand()&3);
820                 for (j=0 ; j<3 ; j++)
821                 {
822                         p->org[j] = diff[j] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[j];
823                         if (randomvel)
824                                 p->vel[j] = dir[j] + (rand()%randomvel)-(randomvel*0.5);
825                         else
826                                 p->vel[j] = 0;
827                 }
828         }
829 }
830
831 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type)
832 {
833         int                     i;
834         particle_t      *p;
835         vec3_t          diff;
836         vec3_t          org;
837         vec3_t          vel;
838         float           t, z;
839         if (!r_particles.value) return; // LordHavoc: particles are optional
840         if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
841         if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
842         if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
843         if (dir[2] < 0) // falling
844         {
845                 t = (maxs[2] - mins[2]) / -dir[2];
846                 z = maxs[2];
847         }
848         else // rising??
849         {
850                 t = (maxs[2] - mins[2]) / dir[2];
851                 z = mins[2];
852         }
853         if (t < 0 || t > 2) // sanity check
854                 t = 2;
855         t += cl.time;
856
857         VectorSubtract(maxs, mins, diff);
858         
859         for (i=0 ; i<count ; i++)
860         {
861                 if (!free_particles)
862                         return;
863                 p = free_particles;
864                 free_particles = p->next;
865                 p->next = active_particles;
866                 active_particles = p;
867
868                 vel[0] = dir[0] + (rand()&31) - 16;
869                 vel[1] = dir[1] + (rand()&31) - 16;
870                 vel[2] = dir[2] + (rand()&63) - 32;
871                 org[0] = diff[0] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[0];
872                 org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1];
873                 org[2] = z;
874
875                 p->scale = 1.5;
876                 p->alpha = 255;
877                 p->die = t;
878                 if (type == 1)
879                 {
880                         p->texnum = particletexture;
881                         p->type = pt_snow;
882                 }
883                 else // 0
884                 {
885                         p->texnum = rainparticletexture;
886                         p->type = pt_static;
887                 }
888                 p->color = colorbase + (rand()&3);
889                 VectorCopy(org, p->org);
890                 VectorCopy(vel, p->vel);
891                 VectorCopy(vel, p->vel2);
892         }
893 }
894
895
896 /*
897 ===============
898 R_LavaSplash
899
900 ===============
901 */
902 void R_LavaSplash (vec3_t org)
903 {
904         int                     i, j, k;
905         particle_t      *p;
906         float           vel;
907         vec3_t          dir;
908         if (!r_particles.value) return; // LordHavoc: particles are optional
909
910         for (i=-16 ; i<16 ; i+=2)
911                 for (j=-16 ; j<16 ; j+=2)
912                         for (k=0 ; k<1 ; k++)
913                         {
914                                 if (!free_particles)
915                                         return;
916                                 p = free_particles;
917                                 free_particles = p->next;
918                                 p->next = active_particles;
919                                 active_particles = p;
920                 
921                                 p->texnum = flareparticletexture;
922                                 p->scale = 10;
923                                 p->alpha = 128;
924                                 p->die = cl.time + 2 + (rand()&31) * 0.02;
925                                 p->color = 224 + (rand()&7);
926                                 p->type = pt_slowgrav;
927                                 
928                                 dir[0] = j*8 + (rand()&7);
929                                 dir[1] = i*8 + (rand()&7);
930                                 dir[2] = 256;
931         
932                                 p->org[0] = org[0] + dir[0];
933                                 p->org[1] = org[1] + dir[1];
934                                 p->org[2] = org[2] + (rand()&63);
935         
936                                 VectorNormalize (dir);                                          
937                                 vel = 50 + (rand()&63);
938                                 VectorScale (dir, vel, p->vel);
939                         }
940 }
941
942 /*
943 ===============
944 R_TeleportSplash
945
946 ===============
947 */
948 void R_TeleportSplash (vec3_t org)
949 {
950         int                     i, j, k;
951         particle_t      *p;
952 //      vec3_t          dir;
953         if (!r_particles.value) return; // LordHavoc: particles are optional
954
955         /*
956         for (i=-16 ; i<16 ; i+=4)
957                 for (j=-16 ; j<16 ; j+=4)
958                         for (k=-24 ; k<32 ; k+=4)
959                         {
960                                 if (!free_particles)
961                                         return;
962                                 p = free_particles;
963                                 free_particles = p->next;
964                                 p->next = active_particles;
965                                 active_particles = p;
966                 
967                                 p->texnum = particletexture;
968                                 p->scale = 2;
969                                 p->alpha = 255;
970                                 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
971                                 p->color = 7 + (rand()&7);
972                                 p->type = pt_slowgrav;
973                                 
974                                 dir[0] = j*8;
975                                 dir[1] = i*8;
976                                 dir[2] = k*8;
977         
978                                 p->org[0] = org[0] + i + (rand()&3);
979                                 p->org[1] = org[1] + j + (rand()&3);
980                                 p->org[2] = org[2] + k + (rand()&3);
981         
982                                 VectorNormalize (dir);                                          
983                                 vel = 50 + (rand()&63);
984                                 VectorScale (dir, vel, p->vel);
985                         }
986         */
987
988         for (i=-24 ; i<24 ; i+=8)
989                 for (j=-24 ; j<24 ; j+=8)
990                         for (k=-24 ; k<32 ; k+=8)
991                         {
992                                 if (!free_particles)
993                                         return;
994                                 p = free_particles;
995                                 free_particles = p->next;
996                                 p->next = active_particles;
997                                 active_particles = p;
998                 
999                                 p->texnum = flareparticletexture;
1000                                 p->scale = 4;
1001                                 p->alpha = (1 + rand()&7) * 32;
1002                                 p->die = cl.time + 5;
1003                                 p->color = 254; //8 + (rand()&7);
1004                                 p->type = pt_fadespark;
1005                                 
1006                                 p->org[0] = org[0] + i + (rand()&7);
1007                                 p->org[1] = org[1] + j + (rand()&7);
1008                                 p->org[2] = org[2] + k + (rand()&7);
1009         
1010                                 p->vel[0] = i*2 + (rand()%25) - 12;
1011                                 p->vel[1] = j*2 + (rand()%25) - 12;
1012                                 p->vel[2] = k*2 + (rand()%25) - 12 + 40;
1013                         }
1014 }
1015
1016 void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
1017 {
1018         vec3_t          vec;
1019         float           len, dec, t, nt, speed;
1020         int                     j, contents, bubbles;
1021         particle_t      *p;
1022         static int      tracercount;
1023         if (!r_particles.value) return; // LordHavoc: particles are optional
1024
1025         t = cl.oldtime;
1026         nt = cl.time;
1027         if (ent->trail_leftover < 0)
1028                 ent->trail_leftover = 0;
1029         t += ent->trail_leftover;
1030         ent->trail_leftover -= (cl.time - cl.oldtime);
1031         if (t >= cl.time)
1032                 return;
1033
1034         contents = Mod_PointInLeaf(start, cl.worldmodel)->contents;
1035         if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA)
1036                 return;
1037
1038         VectorSubtract (end, start, vec);
1039         len = VectorNormalizeLength (vec);
1040         if (len <= 0.01f)
1041                 return;
1042         speed = len / (nt - t);
1043
1044         bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME);
1045
1046         while (t < nt)
1047         {
1048                 if (!free_particles)
1049                         return;
1050                 p = free_particles;
1051                 free_particles = p->next;
1052                 p->next = active_particles;
1053                 active_particles = p;
1054                 
1055                 p->vel[0] = p->vel[1] = p->vel[2] = 0;
1056                 p->die = cl.time + 2;
1057
1058                 switch (type)
1059                 {
1060                         case 0: // rocket trail
1061                         case 1: // grenade trail
1062                                 if (bubbles)
1063                                 {
1064                                         dec = 0.005f;
1065                                         p->texnum = bubbleparticletexture;
1066                                         p->scale = lhrandom(1,2);
1067                                         p->alpha = 255;
1068                                         p->color = (rand()&3)+12;
1069                                         p->type = pt_bubble;
1070                                         p->die = cl.time + 2;
1071                                         for (j=0 ; j<3 ; j++)
1072                                         {
1073                                                 p->vel[j] = (rand()&31)-16;
1074                                                 p->org[j] = start[j] + ((rand()&3)-2);
1075                                         }
1076                                 }
1077                                 else
1078                                 {
1079                                         dec = 0.02f;
1080                                         p->texnum = smokeparticletexture;
1081                                         p->scale = lhrandom(4, 7);
1082                                         p->alpha = 64 + (rand()&31);
1083                                         p->color = (rand()&3)+12;
1084                                         p->type = pt_smoke;
1085                                         p->die = cl.time + 10000;
1086                                         VectorCopy(start, p->org);
1087                                 }
1088                                 break;
1089
1090                                 /*
1091                         case 1: // smoke smoke
1092                                 dec = 0.016f;
1093                                 p->texnum = smokeparticletexture;
1094                                 p->scale = lhrandom(6,9);
1095                                 p->alpha = 64;
1096                                 if (r_smokecolor.value)
1097                                         p->color = r_smokecolor.value;
1098                                 else
1099                                         p->color = (rand()&3)+12;
1100                                 p->type = pt_smoke;
1101                                 p->die = cl.time + 1;
1102                                 VectorCopy(start, p->org);
1103                                 break;
1104                                 */
1105
1106                         case 2: // blood
1107                                 dec = 0.03f;
1108                                 p->texnum = bloodcloudparticletexture;
1109                                 p->scale = lhrandom(8, 12);
1110                                 p->alpha = 255;
1111                                 p->color = (rand()&3)+68;
1112                                 p->type = pt_bloodcloud;
1113                                 p->die = cl.time + 2;
1114                                 for (j=0 ; j<3 ; j++)
1115                                 {
1116                                         p->vel[j] = (rand()&15)-8;
1117                                         p->org[j] = start[j] + ((rand()&3)-2);
1118                                 }
1119                                 break;
1120
1121                         case 3:
1122                         case 5: // tracer
1123                                 dec = 0.01f;
1124                                 p->texnum = flareparticletexture;
1125                                 p->scale = 2;
1126                                 p->alpha = 255;
1127                                 p->die = cl.time + 0.2; //5;
1128                                 p->type = pt_static;
1129                                 if (type == 3)
1130                                         p->color = 52 + ((tracercount&4)<<1);
1131                                 else
1132                                         p->color = 230 + ((tracercount&4)<<1);
1133
1134                                 tracercount++;
1135
1136                                 VectorCopy (start, p->org);
1137                                 if (tracercount & 1)
1138                                 {
1139                                         p->vel[0] = 30*vec[1];
1140                                         p->vel[1] = 30*-vec[0];
1141                                 }
1142                                 else
1143                                 {
1144                                         p->vel[0] = 30*-vec[1];
1145                                         p->vel[1] = 30*vec[0];
1146                                 }
1147                                 break;
1148
1149                         case 4: // slight blood
1150                                 dec = 0.03f; // sparse trail
1151                                 p->texnum = bloodcloudparticletexture;
1152                                 p->scale = lhrandom(8,12);
1153                                 p->alpha = 255;
1154                                 p->color = (rand()&3)+68;
1155                                 p->type = pt_fadespark2;
1156                                 p->die = cl.time + 2;
1157                                 for (j=0 ; j<3 ; j++)
1158                                 {
1159                                         p->vel[j] = (rand()&15)-8;
1160                                         p->org[j] = start[j] + ((rand()&3)-2);
1161                                 }
1162                                 break;
1163
1164                         case 6: // voor trail
1165                                 dec = 0.05f; // sparse trail
1166                                 p->texnum = flareparticletexture;
1167                                 p->scale = lhrandom(4, 8);
1168                                 p->alpha = 255;
1169                                 p->color = 9*16 + 8 + (rand()&3);
1170                                 p->type = pt_fadespark2;
1171                                 p->die = cl.time + 2;
1172                                 for (j=0 ; j<3 ; j++)
1173                                 {
1174                                         p->vel[j] = (rand()&15)-8;
1175                                         p->org[j] = start[j] + ((rand()&3)-2);
1176                                 }
1177                                 break;
1178
1179                         case 7: // Nehahra smoke tracer
1180                                 dec = 0.14f;
1181                                 p->texnum = smokeparticletexture;
1182                                 p->scale = lhrandom(6, 10);
1183                                 p->alpha = 64;
1184                                 p->color = (rand()&3)+12;
1185                                 p->type = pt_smoke;
1186                                 p->die = cl.time + 10000;
1187                                 for (j=0 ; j<3 ; j++)
1188                                         p->org[j] = start[j] + ((rand()&3)-2);
1189                                 break;
1190                 }
1191                 
1192                 t += dec;
1193                 dec *= speed;
1194                 VectorMA (start, dec, vec, start);
1195         }
1196         ent->trail_leftover = t - cl.time;
1197 }
1198
1199 void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
1200 {
1201         vec3_t          vec;
1202         float           len;
1203         particle_t      *p;
1204         static int      tracercount;
1205         if (!r_particles.value) return; // LordHavoc: particles are optional
1206
1207         VectorSubtract (end, start, vec);
1208         len = VectorNormalizeLength (vec);
1209         while (len > 0)
1210         {
1211                 len -= 3;
1212
1213                 if (!free_particles)
1214                         return;
1215                 p = free_particles;
1216                 free_particles = p->next;
1217                 p->next = active_particles;
1218                 active_particles = p;
1219                 
1220                 VectorCopy (vec3_origin, p->vel);
1221
1222                 p->texnum = flareparticletexture;
1223                 p->scale = 8;
1224                 p->alpha = 192;
1225                 p->color = color;
1226                 p->type = pt_smoke;
1227                 p->die = cl.time + 1;
1228                 VectorCopy(start, p->org);
1229 //              for (j=0 ; j<3 ; j++)
1230 //                      p->org[j] = start[j] + ((rand()&15)-8);
1231
1232                 VectorAdd (start, vec, start);
1233         }
1234 }
1235
1236
1237 extern qboolean lighthalf;
1238
1239 /*
1240 ===============
1241 R_DrawParticles
1242 ===============
1243 */
1244 extern  cvar_t  sv_gravity;
1245
1246 void R_DrawParticles (void)
1247 {
1248         particle_t              *p, *kill;
1249         int                             i, r,g,b,a;
1250         float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2;
1251         byte                    *color24;
1252         vec3_t                  up, right, uprightangles, forward2, up2, right2, v;
1253
1254         // LordHavoc: early out condition
1255         if (!active_particles)
1256                 return;
1257
1258         VectorScale (vup, 1.5, up);
1259         VectorScale (vright, 1.5, right);
1260
1261         uprightangles[0] = 0;
1262         uprightangles[1] = r_refdef.viewangles[1];
1263         uprightangles[2] = 0;
1264         AngleVectors (uprightangles, forward2, right2, up2);
1265
1266         frametime = cl.time - cl.oldtime;
1267         time3 = frametime * 15;
1268         time2 = frametime * 10; // 15;
1269         time1 = frametime * 5;
1270         grav = (grav1 = frametime * sv_gravity.value) * 0.05;
1271         dvel = 1+4*frametime;
1272
1273         for ( ;; ) 
1274         {
1275                 kill = active_particles;
1276                 if (kill && kill->die < cl.time)
1277                 {
1278                         active_particles = kill->next;
1279                         kill->next = free_particles;
1280                         free_particles = kill;
1281                         continue;
1282                 }
1283                 break;
1284         }
1285
1286         for (p=active_particles ; p ; p=p->next)
1287         {
1288                 for ( ;; )
1289                 {
1290                         kill = p->next;
1291                         if (kill && kill->die < cl.time)
1292                         {
1293                                 p->next = kill->next;
1294                                 kill->next = free_particles;
1295                                 free_particles = kill;
1296                                 continue;
1297                         }
1298                         break;
1299                 }
1300                 // LordHavoc: 'removed last in list' condition
1301                 if (!p)
1302                         break;
1303
1304                 VectorSubtract(p->org, r_refdef.vieworg, v);
1305                 if (DotProduct(v, v) >= 256.0f)
1306                 {
1307                         scale = p->scale * -0.5;scale2 = p->scale * 0.5;
1308                         color24 = (byte *) &d_8to24table[(int)p->color];
1309                         r = color24[0];
1310                         g = color24[1];
1311                         b = color24[2];
1312                         a = p->alpha;
1313                         if (lighthalf)
1314                         {
1315                                 r >>= 1;
1316                                 g >>= 1;
1317                                 b >>= 1;
1318                         }
1319                         transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
1320                         if (p->texnum == rainparticletexture) // rain streak
1321                         {
1322                                 transpolyvert(p->org[0] + up2[0]*scale  + right2[0]*scale , p->org[1] + up2[1]*scale  + right2[1]*scale , p->org[2] + up2[2]*scale  + right2[2]*scale , 0,1,r,g,b,a);
1323                                 transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a);
1324                                 transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a);
1325                                 transpolyvert(p->org[0] + up2[0]*scale  + right2[0]*scale2, p->org[1] + up2[1]*scale  + right2[1]*scale2, p->org[2] + up2[2]*scale  + right2[2]*scale2, 1,1,r,g,b,a);
1326                         }
1327                         else
1328                         {
1329                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale , p->org[1] + up[1]*scale  + right[1]*scale , p->org[2] + up[2]*scale  + right[2]*scale , 0,1,r,g,b,a);
1330                                 transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a);
1331                                 transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a);
1332                                 transpolyvert(p->org[0] + up[0]*scale  + right[0]*scale2, p->org[1] + up[1]*scale  + right[1]*scale2, p->org[2] + up[2]*scale  + right[2]*scale2, 1,1,r,g,b,a);
1333                         }
1334                         transpolyend();
1335                 }
1336
1337                 p->org[0] += p->vel[0]*frametime;
1338                 p->org[1] += p->vel[1]*frametime;
1339                 p->org[2] += p->vel[2]*frametime;
1340                 
1341                 switch (p->type)
1342                 {
1343                 case pt_static:
1344                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1345                                 p->die = -1;
1346                         break;
1347                 case pt_fire:
1348                         p->ramp += time1;
1349                         if (p->ramp >= 6)
1350                                 p->die = -1;
1351                         else
1352                                 p->color = ramp3[(int)p->ramp];
1353                         p->vel[2] += grav;
1354                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1355                                 p->die = -1;
1356                         break;
1357
1358                 case pt_explode:
1359                         p->ramp += time2;
1360                         if (p->ramp >=8)
1361                                 p->die = -1;
1362                         else
1363                                 p->color = ramp1[(int)p->ramp];
1364 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1365                         for (i=0 ; i<3 ; i++)
1366                                 p->vel[i] *= dvel;
1367 //                      p->vel[2] -= grav;
1368                         break;
1369
1370                 case pt_explode2:
1371                         p->ramp += time3;
1372                         if (p->ramp >= 8 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1373                                 p->die = -1;
1374                         else
1375                                 p->color = ramp2[(int)p->ramp];
1376 //                      p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
1377                         for (i=0 ; i<3 ; i++)
1378                                 p->vel[i] -= p->vel[i]*frametime;
1379 //                      p->vel[2] -= grav;
1380                         break;
1381
1382                 case pt_blob:
1383                         for (i=0 ; i<3 ; i++)
1384                                 p->vel[i] += p->vel[i]*dvel;
1385                         p->vel[2] -= grav;
1386                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1387                                 p->die = -1;
1388                         break;
1389
1390                 case pt_blob2:
1391                         for (i=0 ; i<2 ; i++)
1392                                 p->vel[i] -= p->vel[i]*dvel;
1393                         p->vel[2] -= grav;
1394                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1395                                 p->die = -1;
1396                         break;
1397
1398                 case pt_grav:
1399                         p->vel[2] -= grav1;
1400                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1401                                 p->die = -1;
1402                         break;
1403                 case pt_slowgrav:
1404                         p->vel[2] -= grav;
1405                         if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1406                                 p->die = -1;
1407                         break;
1408 // LordHavoc: gunshot spark showers
1409                 case pt_dust:
1410                         p->ramp += time1;
1411                         p->scale -= frametime * 4;
1412                         if (p->ramp >= 8 || p->scale <= 0 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1413                                 p->die = -1;
1414                         else
1415                                 p->color = ramp3[(int)p->ramp];
1416                         p->vel[2] -= grav1;
1417                         break;
1418 // LordHavoc: for smoke trails
1419                 case pt_smoke:
1420                         p->scale += frametime * 4;
1421                         p->alpha -= frametime * 48;
1422 //                      p->vel[2] += grav;
1423                         if (p->alpha < 1)
1424                                 p->die = -1;
1425                         break;
1426                 case pt_snow:
1427                         if (cl.time > p->time2)
1428                         {
1429                                 p->time2 = cl.time + (rand() & 3) * 0.1;
1430                                 p->vel[0] = (rand()&63)-32 + p->vel2[0];
1431                                 p->vel[1] = (rand()&63)-32 + p->vel2[1];
1432                                 p->vel[2] = (rand()&63)-32 + p->vel2[2];
1433                                 if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY)
1434                                         p->die = -1;
1435                         }
1436                         break;
1437                 case pt_bulletpuff:
1438                         p->scale -= frametime * 64;
1439                         p->alpha -= frametime * 1024;
1440                         p->vel[2] -= grav;
1441                         if (p->alpha < 1 || p->scale < 1)
1442                                 p->die = -1;
1443                         break;
1444                 case pt_bloodcloud:
1445                         p->scale -= frametime * 24;
1446                         p->alpha -= frametime * 128;
1447                         p->vel[2] -= grav;
1448                         if (p->alpha < 1 || p->scale < 1)
1449                                 p->die = -1;
1450                         break;
1451                 case pt_fadespark:
1452                         p->alpha -= frametime * 256;
1453                         p->vel[2] -= grav;
1454                         if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1455                                 p->die = -1;
1456                         break;
1457                 case pt_fadespark2:
1458                         p->alpha -= frametime * 512;
1459                         p->vel[2] -= grav;
1460                         if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1461                                 p->die = -1;
1462                         break;
1463                 case pt_fallfadespark:
1464                         p->alpha -= frametime * 256;
1465                         p->vel[2] -= grav1;
1466                         if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1467                                 p->die = -1;
1468                         break;
1469                 case pt_fallfadespark2:
1470                         p->alpha -= frametime * 512;
1471                         p->vel[2] -= grav1;
1472                         if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_SOLID)
1473                                 p->die = -1;
1474                         break;
1475                 case pt_bubble:
1476                         p->vel[2] += grav1 * 2;
1477                         if (p->vel[2] >= 200)
1478                                 p->vel[2] = 136+rand()&63;
1479                         if (cl.time > p->time2)
1480                         {
1481                                 p->time2 = cl.time + (rand()&7)*0.0625;
1482                                 p->vel[0] = (rand()&63)-32;
1483                                 p->vel[1] = (rand()&63)-32;
1484                         }
1485                         p->alpha -= frametime * 64;
1486                         if (p->alpha < 1 || Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
1487                                 p->die = -1;
1488                         break;
1489                 }
1490         }
1491 }
1492