]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_part.c
disabled texcoord checks in alias models, due to CTF v_star bug
[xonotic/darkplaces.git] / r_part.c
index 5c822d9b8f82d59f27c5a28bdc957f99e7851ece..12a5a6096ed372dfff2a5c7578be8e9ff1115a73 100644 (file)
--- a/r_part.c
+++ b/r_part.c
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-#define MAX_PARTICLES                  2048    // default max # of particles at one
+#define MAX_PARTICLES                  4096    // default max # of particles at one
                                                                                //  time
 #define ABSOLUTE_MIN_PARTICLES 512             // no fewer than this no matter what's
                                                                                //  on the command line
@@ -30,7 +30,7 @@ int           ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
 int            ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
 
 int            particletexture;
-int            smokeparticletexture;
+int            smokeparticletexture[8];
 int            flareparticletexture;
 int            rainparticletexture;
 int            bloodcloudparticletexture;
@@ -43,25 +43,34 @@ int                 r_numparticles;
 
 vec3_t                 r_pright, r_pup, r_ppn;
 
-//extern cvar_t r_particles/*, r_smoke*/, r_smokealpha;
-//cvar_t r_smokecolor = {"r_smokecolor", "0"};
+// LordHavoc: reduced duplicate code, and allow particle allocation system independence
+#define ALLOCPARTICLE \
+       if (!free_particles)\
+               return;\
+       p = free_particles;\
+       free_particles = p->next;\
+       p->next = active_particles;\
+       active_particles = p;
+
+cvar_t r_particles = {"r_particles", "1"};
+cvar_t r_dynamicparticles = {"r_dynamicparticles", "0", TRUE};
 
 void fractalnoise(char *noise, int size);
 void fractalnoise_zeroedge(char *noise, int size);
 
 void R_InitParticleTexture (void)
 {
-       int             x,y,d;
+       int             x,y,d,i;
        float   dx, dy, dz, f, dot;
-       byte    data[64][64][4], noise1[64][64], noise2[64][64];
+       byte    data[32][32][4], noise1[32][32], noise2[32][32];
        vec3_t  normal, light;
 
        particletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, particletexture);
+       glBindTexture(GL_TEXTURE_2D, particletexture);
 
-       for (x=0 ; x<64 ; x++)
+       for (x=0 ; x<32 ; x++)
        {
-               for (y=0 ; y<64 ; y++)
+               for (y=0 ; y<32 ; y++)
                {
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
                        dx = x - 16;
@@ -71,7 +80,7 @@ void R_InitParticleTexture (void)
                        data[y][x][3] = (byte) d;
                }
        }
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
@@ -79,55 +88,66 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
 
-       fractalnoise(&noise1[0][0], 64);
-       fractalnoise(&noise2[0][0], 64);
-       for (y = 0;y < 64;y++)
-               for (x = 0;x < 64;x++)
-               {
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
-                       dx = x - 16;
-                       dy = y - 16;
-                       d = (noise2[y][x] * (255 - (dx*dx+dy*dy))) * (1.0f / 255.0f);
-                       if (d < 0) d = 0;
-                       if (d > 255) d = 255;
-                       data[y][x][3] = (byte) d;
-               }
-
-       /*
-       for (x=0 ; x<34 ; x+=2)
-               for (y=0 ; y<34 ; y+=2)
-                       data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%64)+192;
-       for (x=0 ; x<32 ; x+=2)
-               for (y=0 ; y<32 ; y+=2)
-               {
-                       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;
-                       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;
-                       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;
-               }
-       for (x=0 ; x<64 ; x++)
+       for (i = 0;i < 8;i++)
        {
-               for (y=0 ; y<64 ; y++)
+               fractalnoise(&noise1[0][0], 32);
+               fractalnoise(&noise2[0][0], 32);
+               for (y = 0;y < 32;y++)
+                       for (x = 0;x < 32;x++)
+                       {
+                               data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
+                               dx = x - 16;
+                               dy = y - 16;
+                               d = noise2[y][x] * 4 - 512;
+                               if (d > 0)
+                               {
+                                       if (d > 255)
+                                               d = 255;
+                                       d = (d * (255 - (int) (dx*dx+dy*dy))) >> 8;
+                                       if (d < 0) d = 0;
+                                       if (d > 255) d = 255;
+                                       data[y][x][3] = (byte) d;
+                               }
+                               else
+                                       data[y][x][3] = 0;
+                       }
+
+               /*
+               for (x=0 ; x<34 ; x+=2)
+                       for (y=0 ; y<34 ; y+=2)
+                               data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%32)+192;
+               for (x=0 ; x<32 ; x+=2)
+                       for (y=0 ; y<32 ; y+=2)
+                       {
+                               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;
+                               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;
+                               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;
+                       }
+               for (x=0 ; x<32 ; x++)
                {
-                       //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+64;
-                       dx = x - 16;
-                       dy = y - 16;
-                       d = (255 - (dx*dx+dy*dy));
-                       if (d < 0) d = 0;
-                       data[y][x][3] = (byte) d;
+                       for (y=0 ; y<32 ; y++)
+                       {
+                               //data[y][x][0] = data[y][x][1] = data[y][x][2] = (rand()%192)+32;
+                               dx = x - 16;
+                               dy = y - 16;
+                               d = (255 - (dx*dx+dy*dy));
+                               if (d < 0) d = 0;
+                               data[y][x][3] = (byte) d;
+                       }
                }
+               */
+               smokeparticletexture[i] = texture_extension_number++;
+               glBindTexture(GL_TEXTURE_2D, smokeparticletexture[i]);
+               glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+               glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
-       */
-       smokeparticletexture = texture_extension_number++;
-       glBindTexture(GL_TEXTURE_2D, smokeparticletexture);
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
-       fractalnoise(&noise1[0][0], 64);
-       fractalnoise(&noise2[0][0], 64);
-       for (y = 0;y < 64;y++)
-               for (x = 0;x < 64;x++)
+       fractalnoise(&noise1[0][0], 32);
+       fractalnoise(&noise2[0][0], 32);
+       for (y = 0;y < 32;y++)
+               for (x = 0;x < 32;x++)
                {
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = (noise1[y][x] >> 1) + 128;
                        dx = x - 16;
@@ -140,17 +160,17 @@ void R_InitParticleTexture (void)
 
        bloodcloudparticletexture = texture_extension_number++;
        glBindTexture(GL_TEXTURE_2D, bloodcloudparticletexture);
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        flareparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, flareparticletexture);
+       glBindTexture(GL_TEXTURE_2D, flareparticletexture);
 
-       for (x=0 ; x<64 ; x++)
+       for (x=0 ; x<32 ; x++)
        {
-               for (y=0 ; y<64 ; y++)
+               for (y=0 ; y<32 ; y++)
                {
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
                        dx = x - 16;
@@ -160,7 +180,7 @@ void R_InitParticleTexture (void)
                        data[y][x][3] = (byte) d;
                }
        }
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
@@ -168,11 +188,11 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        rainparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, rainparticletexture);
+       glBindTexture(GL_TEXTURE_2D, rainparticletexture);
 
-       for (x=0 ; x<64 ; x++)
+       for (x=0 ; x<32 ; x++)
        {
-               for (y=0 ; y<64 ; y++)
+               for (y=0 ; y<32 ; y++)
                {
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
                        if (y < 24) // stretch the upper half to make a raindrop
@@ -191,7 +211,7 @@ void R_InitParticleTexture (void)
                        data[y][x][3] = (byte) d;
                }
        }
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
@@ -199,13 +219,13 @@ void R_InitParticleTexture (void)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
        bubbleparticletexture = texture_extension_number++;
-    glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
+       glBindTexture(GL_TEXTURE_2D, bubbleparticletexture);
 
        light[0] = 1;light[1] = 1;light[2] = 1;
        VectorNormalize(light);
-       for (x=0 ; x<64 ; x++)
+       for (x=0 ; x<32 ; x++)
        {
-               for (y=0 ; y<64 ; y++)
+               for (y=0 ; y<32 ; y++)
                {
                        data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
                        dx = x * (1.0 / 16.0) - 1.0;
@@ -230,15 +250,15 @@ void R_InitParticleTexture (void)
                                        f += ((dot *  2) - 1);
                                else if (dot < -0.5) // exterior reflection
                                        f += ((dot * -2) - 1);
-                               f *= 255;
+                               f *= 64;
                                f = bound(0, f, 255);
-                               data[y][x][3] = (byte) d;
+                               data[y][x][3] = (byte) f;
                        }
                        else
                                data[y][x][3] = 0;
                }
        }
-       glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+       glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
@@ -270,7 +290,8 @@ void R_InitParticles (void)
 
        particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
 
-//     Cvar_RegisterVariable (&r_smokecolor);
+       Cvar_RegisterVariable (&r_particles);
+       Cvar_RegisterVariable (&r_dynamicparticles);
        R_InitParticleTexture ();
 }
 
@@ -297,7 +318,7 @@ void R_EntityParticles (entity_t *ent)
        float           sr, sp, sy, cr, cp, cy;
        vec3_t          forward;
        float           dist;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        
        dist = 64;
        count = 50;
@@ -325,17 +346,13 @@ avelocities[0][i] = (rand()&255) * 0.01;
                forward[1] = cp*sy;
                forward[2] = -sp;
 
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
                p->texnum = flareparticletexture;
                p->scale = 2;
                p->alpha = 255;
-               p->die = cl.time + 0.01;
+               p->die = cl.time;
                p->color = 0x6f;
                p->type = pt_explode;
                
@@ -396,10 +413,7 @@ void R_ReadPointFile_f (void)
                        Con_Printf ("Not enough free particles\n");
                        break;
                }
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
                
                p->texnum = particletexture;
                p->scale = 2;
@@ -407,7 +421,7 @@ void R_ReadPointFile_f (void)
                p->die = 99999;
                p->color = (-c)&15;
                p->type = pt_static;
-               VectorCopy (vec3_origin, p->vel);
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
                VectorCopy (org, p->org);
        }
 
@@ -415,6 +429,35 @@ void R_ReadPointFile_f (void)
        Con_Printf ("%i points read\n", c);
 }
 
+/*
+===============
+R_BlastParticles
+
+LordHavoc: blasts away particles in the area, used for explosions to disturb the smoke trail and such
+===============
+*/
+void R_BlastParticles(vec3_t org, vec_t radius, vec_t power)
+{
+       vec3_t v;
+       particle_t *p;
+       vec_t radius2 = radius * radius, speed, dist, scale = 2.5 * power / radius;
+       p = active_particles;
+       if (!p)
+               return;
+       while (p)
+       {
+               VectorSubtract(p->org, org, v);
+               dist = DotProduct(v,v);
+               if (dist < radius2)
+               {
+                       speed = (radius - sqrt(dist)) * scale;
+                       VectorNormalize(v);
+                       VectorMA(p->pushvel, speed, v, p->pushvel);
+               }
+               p = p->next;
+       }
+}
+
 /*
 ===============
 R_ParseParticleEffect
@@ -452,52 +495,63 @@ void R_ParticleExplosion (vec3_t org, int smoke)
 {
        int                     i, j;
        particle_t      *p;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        
        for (i=0 ; i<1024 ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
-               p->texnum = flareparticletexture;
-               p->scale = 4+(rand()&7);
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = particletexture;
+               p->scale = lhrandom(1,3);
                p->alpha = rand()&255;
                p->die = cl.time + 5;
                p->color = ramp1[0];
-               p->ramp = rand()&3;
-               /*
-               if (i & 1)
-                       p->type = pt_explode;
-               else
-                       p->type = pt_explode2;
-               */
+               p->ramp = lhrandom(0, 4);
+//             if (i & 1)
+//                     p->type = pt_explode;
+//             else
+//                     p->type = pt_explode2;
                p->color = ramp1[rand()&7];
                p->type = pt_fallfadespark;
                for (j=0 ; j<3 ; j++)
                {
-                       p->org[j] = org[j] + ((rand()&63)-32);
-                       p->vel[j] = (rand()&511)-256;
+                       p->org[j] = org[j] + lhrandom(-8,8);
+                       p->vel[j] = lhrandom(-192, 192);
                }
-               p->vel[j] += 200;
+               p->vel[2] += 160;
        }
 
-       if (smoke)
+       i = Mod_PointInLeaf(org, cl.worldmodel)->contents;
+       if (i == CONTENTS_SLIME || i == CONTENTS_WATER)
+       {
+               for (i=0 ; i<32 ; i++)
+               {
+                       ALLOCPARTICLE
+
+                       p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       p->texnum = bubbleparticletexture;
+                       p->scale = lhrandom(1,2);
+                       p->alpha = 255;
+                       p->color = (rand()&3)+12;
+                       p->type = pt_bubble;
+                       p->die = cl.time + 2;
+                       for (j=0 ; j<3 ; j++)
+                       {
+                               p->org[j] = org[j] + lhrandom(-16,16);
+                               p->vel[j] = lhrandom(-16,16);
+                       }
+               }
+       }
+       else if (smoke)
        {
                for (i=0 ; i<32 ; i++)
                {
-                       if (!free_particles)
-                               return;
-                       p = free_particles;
-                       free_particles = p->next;
-                       p->next = active_particles;
-                       active_particles = p;
-
-                       p->texnum = smokeparticletexture;
-                       p->scale = 24;
+                       ALLOCPARTICLE
+
+                       p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       p->texnum = smokeparticletexture[rand()&7];
+                       p->scale = 12;
                        p->alpha = 80;
                        p->die = cl.time + 2;
                        p->type = pt_smoke;
@@ -522,19 +576,15 @@ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
        int                     i, j;
        particle_t      *p;
        int                     colorMod = 0;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        for (i=0; i<512; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
-               p->texnum = flareparticletexture;
-               p->scale = 8;
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = smokeparticletexture[rand()&7];
+               p->scale = 1.5;
                p->alpha = 255;
                p->die = cl.time + 0.3;
                p->color = colorStart + (colorMod % colorLength);
@@ -543,8 +593,8 @@ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
                p->type = pt_blob;
                for (j=0 ; j<3 ; j++)
                {
-                       p->org[j] = org[j] + ((rand()%32)-16);
-                       p->vel[j] = (rand()%512)-256;
+                       p->org[j] = org[j] + ((rand()&15)-8);
+                       p->vel[j] = lhrandom(-192, 192);
                }
        }
 }
@@ -559,19 +609,15 @@ void R_BlobExplosion (vec3_t org)
 {
        int                     i, j;
        particle_t      *p;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        
        for (i=0 ; i<1024 ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
-               p->texnum = flareparticletexture;
-               p->scale = 8;
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = smokeparticletexture[rand()&7];
+               p->scale = 2;
                p->alpha = 255;
                p->die = cl.time + 1 + (rand()&8)*0.05;
 
@@ -582,7 +628,7 @@ void R_BlobExplosion (vec3_t org)
                        for (j=0 ; j<3 ; j++)
                        {
                                p->org[j] = org[j] + ((rand()%32)-16);
-                               p->vel[j] = (rand()%512)-256;
+                               p->vel[j] = lhrandom(-128, 128);
                        }
                }
                else
@@ -592,9 +638,11 @@ void R_BlobExplosion (vec3_t org)
                        for (j=0 ; j<3 ; j++)
                        {
                                p->org[j] = org[j] + ((rand()%32)-16);
-                               p->vel[j] = (rand()%512)-256;
+                               p->vel[j] = lhrandom(-128, 128);
                        }
                }
+               p->vel[0] *= 0.25;
+               p->vel[1] *= 0.25;
        }
 }
 
@@ -606,59 +654,39 @@ R_RunParticleEffect
 */
 void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
 {
-       int                     i, j;
+       int                     j;
        particle_t      *p;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        
-       for (i=0 ; i<count ; i++)
+       if (count == 1024)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
-
-               if (count == 1024)
-               {       // rocket explosion
-                       p->texnum = flareparticletexture;
-                       p->scale = 8;
-                       p->alpha = 255;
-                       p->die = cl.time + 5;
-                       p->color = ramp1[0];
-                       p->ramp = rand()&3;
-                       if (i & 1)
-                       {
-                               p->type = pt_explode;
-                               for (j=0 ; j<3 ; j++)
-                               {
-                                       p->org[j] = org[j] + ((rand()%32)-16);
-                                       p->vel[j] = (rand()%512)-256;
-                               }
-                       }
-                       else
-                       {
-                               p->type = pt_explode2;
-                               for (j=0 ; j<3 ; j++)
-                               {
-                                       p->org[j] = org[j] + ((rand()%32)-16);
-                                       p->vel[j] = (rand()%512)-256;
-                               }
-                       }
+               R_ParticleExplosion(org, false);
+               return;
+       }
+       while (count)
+       {
+               ALLOCPARTICLE
+               if (count & 7)
+               {
+                       p->alpha = (count & 7) * 16 + (rand()&15);
+                       count &= ~7;
                }
                else
                {
-                       p->texnum = flareparticletexture;
-                       p->scale = 8;
-                       p->alpha = 255;
-                       p->die = cl.time + 0.1*(rand()%5);
-                       p->color = (color&~7) + (rand()&7);
-                       p->type = pt_static; //slowgrav;
-                       for (j=0 ; j<3 ; j++)
-                       {
-                               p->org[j] = org[j] + ((rand()&15)-8);
-                               p->vel[j] = dir[j]*15;// + (rand()%300)-150;
-                       }
+                       p->alpha = 128;
+                       count -= 8;
+               }
+
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->texnum = particletexture;
+               p->scale = 6;
+               p->die = cl.time + 1; //lhrandom(0.1, 0.5);
+               p->color = (color&~7) + (rand()&7);
+               p->type = pt_fade; //static; //slowgrav;
+               for (j=0 ; j<3 ; j++)
+               {
+                       p->org[j] = org[j] + ((rand()&15)-8);
+                       p->vel[j] = dir[j]*15;// + (rand()%300)-150;
                }
        }
 }
@@ -674,18 +702,14 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
 {
        int                     i, j;
        particle_t      *p;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
-       if (!free_particles)
-               return;
-       p = free_particles;
-       free_particles = p->next;
-       p->next = active_particles;
-       active_particles = p;
+       ALLOCPARTICLE
+       p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
        if (type == 0) // sparks
        {
-               p->texnum = smokeparticletexture;
-               p->scale = 20;
+               p->texnum = smokeparticletexture[rand()&7];
+               p->scale = 15;
                p->alpha = 64;
                p->color = (rand()&3)+12;
                p->type = pt_bulletpuff;
@@ -695,8 +719,8 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
        }
        else // blood
        {
-               p->texnum = bloodcloudparticletexture;
-               p->scale = 24;
+               p->texnum = smokeparticletexture[rand()&7];
+               p->scale = 12;
                p->alpha = 128;
                p->color = (rand()&3)+68;
                p->type = pt_bloodcloud;
@@ -707,15 +731,11 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count, int type)
        }
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = flareparticletexture;
-               p->scale = 5;
+               p->scale = 2;
                p->alpha = 255;
                p->die = cl.time + 0.0625 * (rand()&15);
                /*
@@ -753,7 +773,7 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
        vec3_t          diff;
        vec3_t          center;
        vec3_t          velscale;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        VectorSubtract(maxs, mins, diff);
        center[0] = (mins[0] + maxs[0]) * 0.5;
@@ -765,15 +785,11 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count)
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = bloodcloudparticletexture;
-               p->scale = 24;
+               p->scale = 12;
                p->alpha = 96 + (rand()&63);
                p->die = cl.time + 2; //0.015625 * (rand()%128);
                p->type = pt_fadespark;
@@ -793,7 +809,7 @@ void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        particle_t      *p;
        vec3_t          diff;
        float           t;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
        if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
        if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
@@ -802,15 +818,11 @@ void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                p->texnum = flareparticletexture;
-               p->scale = 12;
+               p->scale = 6;
                p->alpha = 255;
                p->die = cl.time + 1 + (rand()&15)*0.0625;
                if (gravity)
@@ -837,7 +849,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        vec3_t          org;
        vec3_t          vel;
        float           t, z;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
        if (maxs[0] <= mins[0]) {t = mins[0];mins[0] = maxs[0];maxs[0] = t;}
        if (maxs[1] <= mins[1]) {t = mins[1];mins[1] = maxs[1];maxs[1] = t;}
        if (maxs[2] <= mins[2]) {t = mins[2];mins[2] = maxs[2];maxs[2] = t;}
@@ -859,12 +871,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
        
        for (i=0 ; i<count ; i++)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
 
                vel[0] = dir[0] + (rand()&31) - 16;
                vel[1] = dir[1] + (rand()&31) - 16;
@@ -873,7 +880,8 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
                org[1] = diff[1] * (float) (rand()&1023) * (1.0 / 1024.0) + mins[1];
                org[2] = z;
 
-               p->scale = 6;
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+               p->scale = 1.5;
                p->alpha = 255;
                p->die = t;
                if (type == 1)
@@ -889,6 +897,7 @@ void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorb
                p->color = colorbase + (rand()&3);
                VectorCopy(org, p->org);
                VectorCopy(vel, p->vel);
+               VectorCopy(vel, p->vel2);
        }
 }
 
@@ -905,22 +914,18 @@ void R_LavaSplash (vec3_t org)
        particle_t      *p;
        float           vel;
        vec3_t          dir;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        for (i=-16 ; i<16 ; i+=2)
                for (j=-16 ; j<16 ; j+=2)
                        for (k=0 ; k<1 ; k++)
                        {
-                               if (!free_particles)
-                                       return;
-                               p = free_particles;
-                               free_particles = p->next;
-                               p->next = active_particles;
-                               active_particles = p;
+                               ALLOCPARTICLE
                
+                               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                                p->texnum = flareparticletexture;
-                               p->scale = 24;
-                               p->alpha = 255;
+                               p->scale = 10;
+                               p->alpha = 128;
                                p->die = cl.time + 2 + (rand()&31) * 0.02;
                                p->color = 224 + (rand()&7);
                                p->type = pt_slowgrav;
@@ -950,20 +955,17 @@ void R_TeleportSplash (vec3_t org)
        int                     i, j, k;
        particle_t      *p;
 //     vec3_t          dir;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        /*
        for (i=-16 ; i<16 ; i+=4)
                for (j=-16 ; j<16 ; j+=4)
                        for (k=-24 ; k<32 ; k+=4)
                        {
-                               if (!free_particles)
-                                       return;
-                               p = free_particles;
-                               free_particles = p->next;
-                               p->next = active_particles;
-                               active_particles = p;
+                               ALLOCPARTICLE
                
+                               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                               p->contents = 0;
                                p->texnum = particletexture;
                                p->scale = 2;
                                p->alpha = 255;
@@ -989,16 +991,12 @@ void R_TeleportSplash (vec3_t org)
                for (j=-24 ; j<24 ; j+=8)
                        for (k=-24 ; k<32 ; k+=8)
                        {
-                               if (!free_particles)
-                                       return;
-                               p = free_particles;
-                               free_particles = p->next;
-                               p->next = active_particles;
-                               active_particles = p;
+                               ALLOCPARTICLE
                
+                               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
                                p->texnum = flareparticletexture;
-                               p->scale = 8;
-                               p->alpha = (1 + rand()&7) * 32;
+                               p->scale = 4;
+                               p->alpha = lhrandom(32,256);
                                p->die = cl.time + 5;
                                p->color = 254; //8 + (rand()&7);
                                p->type = pt_fadespark;
@@ -1016,11 +1014,11 @@ void R_TeleportSplash (vec3_t org)
 void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
 {
        vec3_t          vec;
-       float           len, dec, t, nt, speed;
+       float           len, dec = 0, t, nt, speed;
        int                     j, contents, bubbles;
        particle_t      *p;
        static int      tracercount;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        t = cl.oldtime;
        nt = cl.time;
@@ -1045,14 +1043,9 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
 
        while (t < nt)
        {
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
                
-               p->vel[0] = p->vel[1] = p->vel[2] = 0;
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
                p->die = cl.time + 2;
 
                switch (type)
@@ -1061,14 +1054,11 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                        case 1: // grenade trail
                                if (bubbles)
                                {
-                                       dec = 0.01f;
+                                       dec = 0.005f;
                                        p->texnum = bubbleparticletexture;
-                                       p->scale = 6+(rand()&3);
+                                       p->scale = lhrandom(1,2);
                                        p->alpha = 255;
-//                                     if (r_smokecolor.value)
-//                                             p->color = r_smokecolor.value;
-//                                     else
-                                               p->color = (rand()&3)+12;
+                                       p->color = (rand()&3)+12;
                                        p->type = pt_bubble;
                                        p->die = cl.time + 2;
                                        for (j=0 ; j<3 ; j++)
@@ -1079,16 +1069,13 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                                }
                                else
                                {
-                                       dec = 0.03f;
-                                       p->texnum = smokeparticletexture;
-                                       p->scale = 12+(rand()&7);
+                                       dec = 0.02f;
+                                       p->texnum = smokeparticletexture[rand()&7];
+                                       p->scale = lhrandom(6, 10);
                                        p->alpha = 64 + (rand()&31);
-//                                     if (r_smokecolor.value)
-//                                             p->color = r_smokecolor.value;
-//                                     else
-                                               p->color = (rand()&3)+12;
+                                       p->color = (rand()&3)+12;
                                        p->type = pt_smoke;
-                                       p->die = cl.time + 2;
+                                       p->die = cl.time + 10000;
                                        VectorCopy(start, p->org);
                                }
                                break;
@@ -1097,7 +1084,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                        case 1: // smoke smoke
                                dec = 0.016f;
                                p->texnum = smokeparticletexture;
-                               p->scale = 12+rand()&7;
+                               p->scale = lhrandom(6,9);
                                p->alpha = 64;
                                if (r_smokecolor.value)
                                        p->color = r_smokecolor.value;
@@ -1110,9 +1097,9 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                                */
 
                        case 2: // blood
-                               dec = 0.03f;
-                               p->texnum = bloodcloudparticletexture;
-                               p->scale = 20+(rand()&7);
+                               dec = 0.025f;
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(6, 8);
                                p->alpha = 255;
                                p->color = (rand()&3)+68;
                                p->type = pt_bloodcloud;
@@ -1128,7 +1115,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                        case 5: // tracer
                                dec = 0.01f;
                                p->texnum = flareparticletexture;
-                               p->scale = 4;
+                               p->scale = 2;
                                p->alpha = 255;
                                p->die = cl.time + 0.2; //5;
                                p->type = pt_static;
@@ -1153,10 +1140,10 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
                                break;
 
                        case 4: // slight blood
-                               dec = 0.03f; // sparse trail
-                               p->texnum = bloodcloudparticletexture;
-                               p->scale = 20+(rand()&7);
-                               p->alpha = 255;
+                               dec = 0.025f; // sparse trail
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(6, 8);
+                               p->alpha = 192;
                                p->color = (rand()&3)+68;
                                p->type = pt_fadespark2;
                                p->die = cl.time + 2;
@@ -1169,8 +1156,8 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
 
                        case 6: // voor trail
                                dec = 0.05f; // sparse trail
-                               p->texnum = flareparticletexture;
-                               p->scale = 20+(rand()&7);
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(3, 5);
                                p->alpha = 255;
                                p->color = 9*16 + 8 + (rand()&3);
                                p->type = pt_fadespark2;
@@ -1184,12 +1171,12 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent)
 
                        case 7: // Nehahra smoke tracer
                                dec = 0.14f;
-                               p->texnum = smokeparticletexture;
-                               p->scale = 12+(rand()&7);
+                               p->texnum = smokeparticletexture[rand()&7];
+                               p->scale = lhrandom(8, 12);
                                p->alpha = 64;
                                p->color = (rand()&3)+12;
                                p->type = pt_smoke;
-                               p->die = cl.time + 1;
+                               p->die = cl.time + 10000;
                                for (j=0 ; j<3 ; j++)
                                        p->org[j] = start[j] + ((rand()&3)-2);
                                break;
@@ -1207,8 +1194,7 @@ void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
        vec3_t          vec;
        float           len;
        particle_t      *p;
-       static int      tracercount;
-//     if (!r_particles.value) return; // LordHavoc: particles are optional
+       if (!r_particles.value) return; // LordHavoc: particles are optional
 
        VectorSubtract (end, start, vec);
        len = VectorNormalizeLength (vec);
@@ -1216,17 +1202,12 @@ void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
        {
                len -= 3;
 
-               if (!free_particles)
-                       return;
-               p = free_particles;
-               free_particles = p->next;
-               p->next = active_particles;
-               active_particles = p;
+               ALLOCPARTICLE
                
-               VectorCopy (vec3_origin, p->vel);
+               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = p->vel[0] = p->vel[1] = p->vel[2] = 0;
 
                p->texnum = flareparticletexture;
-               p->scale = 16;
+               p->scale = 8;
                p->alpha = 192;
                p->color = color;
                p->type = pt_smoke;
@@ -1240,7 +1221,6 @@ void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent)
 }
 
 
-//extern qboolean isG200, isATI, isRagePro;
 extern qboolean lighthalf;
 
 /*
@@ -1249,36 +1229,20 @@ R_DrawParticles
 ===============
 */
 extern cvar_t  sv_gravity;
+void R_CompleteLightPoint (vec3_t color, vec3_t p);
 
 void R_DrawParticles (void)
 {
        particle_t              *p, *kill;
-       int                             i, /*texnum, */r,g,b,a;
-       float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2;
+       int                             i, r,g,b,a;
+       float                   grav, grav1, time1, time2, time3, dvel, frametime, scale, scale2, f1, f2;
        byte                    *color24;
-       vec3_t                  up, right, uprightangles, forward2, up2, right2, v;
+       vec3_t                  up, right, uprightangles, forward2, up2, right2, v, tempcolor;
 
        // LordHavoc: early out condition
        if (!active_particles)
                return;
 
-       /*
-       texnum = particletexture;
-    glBindTexture(GL_TEXTURE_2D, texnum);
-       glEnable (GL_BLEND);
-       // LordHavoc: Matrox G200 cards can't handle per pixel alpha at all...
-       // and ATI Rage Pro can't modulate a per pixel alpha texture
-       if (isG200 || isRagePro)
-               glEnable(GL_ALPHA_TEST);
-       else
-               glDisable(GL_ALPHA_TEST);
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       glDepthMask(0); // disable zbuffer updates
-       glShadeModel(GL_FLAT);
-       glBegin (GL_TRIANGLES);
-       */
-
        VectorScale (vup, 1.5, up);
        VectorScale (vright, 1.5, right);
 
@@ -1328,51 +1292,7 @@ void R_DrawParticles (void)
                VectorSubtract(p->org, r_refdef.vieworg, v);
                if (DotProduct(v, v) >= 256.0f)
                {
-                       scale = p->scale * -0.25;scale2 = p->scale * 0.75;
-                       /*
-                       if (p->texnum != texnum)
-                       {
-                               texnum = p->texnum;
-                               glEnd();
-                               glBindTexture(GL_TEXTURE_2D, texnum);
-                               glBegin(GL_TRIANGLES);
-                       }
-                       if (lighthalf)
-                       {
-                               color24 = (byte *)&d_8to24table[(int)p->color];
-                               if (p->texnum == smokeparticletexture)
-                                       glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) (p->alpha*r_smokealpha.value));
-                               else
-                                       glColor4ub((byte) (color24[0] >> 1), (byte) (color24[1] >> 1), (byte) (color24[2] >> 1), (byte) p->alpha);
-                       }
-                       else
-                       {
-                               color24 = (byte *) &d_8to24table[(int)p->color];
-                               if (p->texnum == smokeparticletexture)
-                                       glColor4ub(color24[0], color24[1], color24[2], (byte) (p->alpha*r_smokealpha.value));
-                               else
-                                       glColor4ub(color24[0], color24[1], color24[2], (byte) p->alpha);
-                       }
-                       if (p->texnum == rainparticletexture) // rain streak
-                       {
-                               glTexCoord2f (0,0);
-                               glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale );
-                               glTexCoord2f (1,0);
-                               glVertex3f (p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale );
-                               glTexCoord2f (0,1);
-                               glVertex3f (p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2);
-                       }
-                       else
-                       {
-                               glTexCoord2f (0,0);
-                               // LordHavoc: centered particle sprites
-                               glVertex3f (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 );
-                               glTexCoord2f (1,0);
-                               glVertex3f (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 );
-                               glTexCoord2f (0,1);
-                               glVertex3f (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);
-                       }
-                       */
+                       scale = p->scale * -0.5;scale2 = p->scale * 0.5;
                        color24 = (byte *) &d_8to24table[(int)p->color];
                        r = color24[0];
                        g = color24[1];
@@ -1384,25 +1304,54 @@ void R_DrawParticles (void)
                                g >>= 1;
                                b >>= 1;
                        }
+                       if (r_dynamicparticles.value)
+                       {
+                               R_CompleteLightPoint(tempcolor, p->org);
+                               r = (r * (int) tempcolor[0]) >> 7;
+                               g = (g * (int) tempcolor[1]) >> 7;
+                               b = (b * (int) tempcolor[2]) >> 7;
+                       }
                        transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
                        if (p->texnum == rainparticletexture) // rain streak
                        {
-                               transpolyvert(p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 0,0,r,g,b,a);
-                               transpolyvert(p->org[0] + right2[0]*scale , p->org[1] + right2[1]*scale , p->org[2] + right2[2]*scale , 1,0,r,g,b,a);
-                               transpolyvert(p->org[0] + right2[0]*scale2, p->org[1] + right2[1]*scale2, p->org[2] + right2[2]*scale2, 0,1,r,g,b,a);
+                               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);
+                               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);
+                               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);
+                               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);
                        }
                        else
                        {
-                               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,0,r,g,b,a);
-                               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 , 1,0,r,g,b,a);
-                               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, 0,1,r,g,b,a);
+                               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);
+                               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);
+                               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);
+                               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);
                        }
                        transpolyend();
                }
 
-               p->org[0] += p->vel[0]*frametime;
-               p->org[1] += p->vel[1]*frametime;
-               p->org[2] += p->vel[2]*frametime;
+               if (p->pushvel[0] || p->pushvel[1] || p->pushvel[2])
+               {
+                       p->org[0] += (p->vel[0]+p->pushvel[0])*frametime;
+                       p->org[1] += (p->vel[1]+p->pushvel[1])*frametime;
+                       p->org[2] += (p->vel[2]+p->pushvel[2])*frametime;
+                       f1 = sqrt(DotProduct(p->pushvel,p->pushvel));
+                       f2 = f1 - frametime * 32;
+                       if (f2 <= 0)
+                               p->pushvel[0] = p->pushvel[1] = p->pushvel[2] = 0;
+                       else
+                       {
+                               f2 /= f1;
+                               p->pushvel[0] *= f2;
+                               p->pushvel[1] *= f2;
+                               p->pushvel[2] *= f2;
+                       }
+               }
+               else
+               {
+                       p->org[0] += p->vel[0]*frametime;
+                       p->org[1] += p->vel[1]*frametime;
+                       p->org[2] += p->vel[2]*frametime;
+               }
                
                switch (p->type)
                {
@@ -1431,14 +1380,15 @@ void R_DrawParticles (void)
 
                case pt_explode2:
                        p->ramp += time3;
-                       if (p->ramp >=8)
+                       if (p->ramp >= 8)
                                p->die = -1;
                        else
                                p->color = ramp2[(int)p->ramp];
 //                     p->vel[2] -= grav1; // LordHavoc: apply full gravity to explosion sparks
                        for (i=0 ; i<3 ; i++)
-                               p->vel[i] -= p->vel[i]*frametime;
-//                     p->vel[2] -= grav;
+//                             p->vel[i] -= p->vel[i]*frametime;
+                               p->vel[i] *= dvel;
+////                   p->vel[2] -= grav;
                        break;
 
                case pt_blob:
@@ -1471,18 +1421,19 @@ void R_DrawParticles (void)
                        break;
 // LordHavoc: for smoke trails
                case pt_smoke:
-                       p->scale += frametime * 16;
-                       p->alpha -= frametime * 64;
-                       p->vel[2] += grav;
+                       p->scale += frametime * 4;
+                       p->alpha -= frametime * 128;
+//                     p->vel[2] += grav;
                        if (p->alpha < 1)
                                p->die = -1;
                        break;
                case pt_snow:
                        if (cl.time > p->time2)
                        {
-                               p->time2 = cl.time + 0.4;
-                               p->vel[0] = (rand()&63)-32;
-                               p->vel[1] = (rand()&63)-32;
+                               p->time2 = cl.time + (rand() & 3) * 0.1;
+                               p->vel[0] = (rand()&63)-32 + p->vel2[0];
+                               p->vel[1] = (rand()&63)-32 + p->vel2[1];
+                               p->vel[2] = (rand()&63)-32 + p->vel2[2];
                        }
                        break;
                case pt_bulletpuff:
@@ -1493,8 +1444,8 @@ void R_DrawParticles (void)
                                p->die = -1;
                        break;
                case pt_bloodcloud:
-                       p->scale -= frametime * 24;
-                       p->alpha -= frametime * 128;
+                       p->scale += frametime * 4;
+                       p->alpha -= frametime * 64;
                        p->vel[2] -= grav;
                        if (p->alpha < 1 || p->scale < 1)
                                p->die = -1;
@@ -1523,28 +1474,28 @@ void R_DrawParticles (void)
                        if (p->alpha < 1)
                                p->die = -1;
                        break;
+               case pt_fade:
+                       p->alpha -= frametime * 512;
+                       if (p->alpha < 1)
+                               p->die = -1;
+                       break;
                case pt_bubble:
-                       p->vel[2] += grav1;
-                       if (p->vel[2] >= 100)
-                               p->vel[2] = 68+rand()&31;
+                       if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY)
+                               p->die = -1;
+                       p->vel[2] += grav1 * 2;
+                       if (p->vel[2] >= 200)
+                               p->vel[2] = lhrandom(130, 200);
                        if (cl.time > p->time2)
                        {
-                               p->time2 = cl.time + (rand()&7)*0.0625;
-                               p->vel[0] = (rand()&63)-32;
-                               p->vel[1] = (rand()&63)-32;
+                               p->time2 = cl.time + lhrandom(0, 0.5);
+                               p->vel[0] = lhrandom(-32,32);
+                               p->vel[1] = lhrandom(-32,32);
                        }
-                       p->alpha -= frametime * 32;
+                       p->alpha -= frametime * 64;
                        if (p->alpha < 1)
                                p->die = -1;
                        break;
                }
        }
-
-       /*
-       glEnd ();
-       glShadeModel(GL_SMOOTH);
-       glDepthMask(1); // enable zbuffer updates
-       glDisable (GL_BLEND);
-       */
 }