X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=r_part.c;h=04d8ac9aa64b776f6150573f63963e98d4a39bd8;hb=22a0b07d1f738b7f5640faad26baed659cc73188;hp=24824c2fb508bd62c6c845d26f8de1d99c94250e;hpb=13bc89911ececa44c12f5a8f7d311199df60ee20;p=xonotic%2Fdarkplaces.git diff --git a/r_part.c b/r_part.c index 24824c2f..04d8ac9a 100644 --- a/r_part.c +++ b/r_part.c @@ -25,8 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // LordHavoc: added dust, smoke, snow, bloodcloud, and many others typedef enum { - pt_static, pt_grav, pt_blob, pt_blob2, pt_smoke, pt_snow, pt_bloodcloud, - pt_fadespark, pt_fadespark2, pt_fallfadespark, pt_fallfadespark2, pt_bubble, pt_fade, pt_smokecloud + pt_static, pt_grav, pt_blob, pt_blob2, pt_smoke, pt_snow, pt_rain, pt_bloodcloud, pt_fallfadespark, pt_bubble, pt_fade, pt_smokecloud, pt_splash } ptype_t; typedef struct particle_s @@ -36,11 +35,11 @@ typedef struct particle_s vec3_t vel; float die; ptype_t type; - // LordHavoc: added for improved particle effects float scale; short texnum; float alpha; // 0-255 float time2; // used for various things (snow fluttering, for example) + vec3_t oldorg; vec3_t vel2; // used for snow fluttering (base velocity, wind for instance) } particle_t; @@ -70,104 +69,110 @@ particle_t **freeparticles; // list used only in compacting particles array 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); +byte shadebubble(float dx, float dy, vec3_t light) +{ + float dz, f, dot; + vec3_t normal; + if ((dx*dx+dy*dy) < 1) // it does hit the sphere + { + dz = 1 - (dx*dx+dy*dy); + f = 0; + // back side + normal[0] = dx;normal[1] = dy;normal[2] = dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + // front side + normal[0] = dx;normal[1] = dy;normal[2] = -dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + f *= 128; + f += 16; // just to give it a haze so you can see the outline + f = bound(0, f, 255); + return (byte) f; + } + else + return 0; +} void R_InitParticleTexture (void) { - int x,y,d,i; - float dx, dy, dz, f, dot; - byte data[32][32][4], noise1[32][32], noise2[32][32]; - vec3_t normal, light; - - particletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, particletexture); + int x,y,d,i,m; + float dx, dy; + byte data[32][32][4], noise1[128][128], noise2[128][128]; + vec3_t light; - for (x=0 ; x<32 ; x++) + for (y = 0;y < 32;y++) { - for (y=0 ; y<32 ; y++) + dy = y - 16; + for (x = 0;x < 32;x++) { data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; dx = x - 16; - dy = y - 16; d = (255 - (dx*dx+dy*dy)); if (d < 0) d = 0; data[y][x][3] = (byte) d; } } - 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); - + particletexture = GL_LoadTexture ("particletexture", 32, 32, &data[0][0][0], true, true, 4); for (i = 0;i < 8;i++) { - fractalnoise(&noise1[0][0], 32); - fractalnoise(&noise2[0][0], 32); - for (y = 0;y < 32;y++) - for (x = 0;x < 32;x++) + do + { + fractalnoise(&noise1[0][0], 128, 8); + fractalnoise(&noise2[0][0], 128, 16); + m = 0; + for (y = 0;y < 32;y++) { - 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) + for (x = 0;x < 32;x++) { - 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; + int j; + j = (noise1[y][x] - 128) * 2 + 128; + if (j < 0) j = 0; + if (j > 255) j = 255; + data[y][x][0] = data[y][x][1] = data[y][x][2] = j; + dx = x - 16; + d = (noise2[y][x] - 128) * 4 + 128; + if (d > 0) + { + d = (d * (255 - (int) (dx*dx+dy*dy))) >> 8; + //j = (sqrt(dx*dx+dy*dy) * 2.0f - 16.0f); + //if (j > 0) + // d = (d * (255 - j*j)) >> 8; + if (d < 0) d = 0; + if (d > 255) d = 255; + data[y][x][3] = (byte) d; + if (m < d) + m = d; + } } - else - data[y][x][3] = 0; } + } + while (m < 192); - 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[i] = GL_LoadTexture (va("smokeparticletexture%d", i), 32, 32, &data[0][0][0], true, true, 4); } - rainparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, rainparticletexture); - + light[0] = 1;light[1] = 1;light[2] = 1; + VectorNormalize(light); for (x=0 ; x<32 ; x++) { 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 - { - dx = (x - 16)*2; - dy = (y - 24)*2/3; - d = (255 - (dx*dx+dy*dy))/2; - } - else - { - dx = (x - 16)*2; - dy = (y - 24)*2; - d = (255 - (dx*dx+dy*dy))/2; - } - if (d < 0) d = 0; - data[y][x][3] = (byte) d; + data[y][x][3] = shadebubble((x - 16) * (1.0 / 8.0), y < 24 ? (y - 24) * (1.0 / 24.0) : (y - 24) * (1.0 / 8.0), light); } } - 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); - - bubbleparticletexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, bubbleparticletexture); + rainparticletexture = GL_LoadTexture ("rainparticletexture", 32, 32, &data[0][0][0], true, true, 4); light[0] = 1;light[1] = 1;light[2] = 1; VectorNormalize(light); @@ -176,42 +181,23 @@ void R_InitParticleTexture (void) 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; - dy = y * (1.0 / 16.0) - 1.0; - if (dx*dx+dy*dy < 1) // it does hit the sphere - { - dz = 1 - (dx*dx+dy*dy); - f = 0; - // back side - normal[0] = dx;normal[1] = dy;normal[2] = dz; - VectorNormalize(normal); - dot = DotProduct(normal, light); - if (dot > 0.5) // interior reflection - f += ((dot * 2) - 1); - else if (dot < -0.5) // exterior reflection - f += ((dot * -2) - 1); - // front side - normal[0] = dx;normal[1] = dy;normal[2] = -dz; - VectorNormalize(normal); - dot = DotProduct(normal, light); - if (dot > 0.5) // interior reflection - f += ((dot * 2) - 1); - else if (dot < -0.5) // exterior reflection - f += ((dot * -2) - 1); - f *= 64; - f = bound(0, f, 255); - data[y][x][3] = (byte) f; - } - else - data[y][x][3] = 0; + data[y][x][3] = shadebubble((x - 16) * (1.0 / 16.0), (y - 16) * (1.0 / 16.0), light); } } - glTexImage2D (GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + bubbleparticletexture = GL_LoadTexture ("bubbleparticletexture", 32, 32, &data[0][0][0], true, true, 4); +} - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +void r_part_start() +{ + particles = (particle_t *) malloc (r_numparticles * sizeof(particle_t)); + freeparticles = (void *) malloc (r_numparticles * sizeof(particle_t *)); + R_InitParticleTexture (); +} - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +void r_part_shutdown() +{ + free(particles); + free(freeparticles); } /* @@ -219,7 +205,7 @@ void R_InitParticleTexture (void) R_InitParticles =============== */ -void R_InitParticles (void) +void R_Particles_Init (void) { int i; @@ -236,12 +222,10 @@ void R_InitParticles (void) r_numparticles = MAX_PARTICLES; } - particles = (particle_t *) Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles"); - freeparticles = (void *) Hunk_AllocName (r_numparticles * sizeof(particle_t *), "particles"); - Cvar_RegisterVariable (&r_particles); Cvar_RegisterVariable (&r_dynamicparticles); - R_InitParticleTexture (); + + R_RegisterModule("R_Particles", r_part_start, r_part_shutdown); } #define particle(ptype, pcolor, ptex, pscale, palpha, ptime, px, py, pz, pvx, pvy, pvz)\ @@ -496,12 +480,20 @@ void R_ParticleExplosion (vec3_t org, int smoke) int i; if (!r_particles.value) return; // LordHavoc: particles are optional - particle(pt_smokecloud, (rand()&7) + 8, smokeparticletexture[rand()&7], 30, 96, 2, org[0], org[1], org[2], 0, 0, 0); + particle(pt_smokecloud, (rand()&7) + 8, smokeparticletexture[rand()&7], 30, 255, 2, org[0], org[1], org[2], 0, 0, 0); i = Mod_PointInLeaf(org, cl.worldmodel)->contents; if (i == CONTENTS_SLIME || i == CONTENTS_WATER) - for (i=0 ; i<32 ; i++) - particle2(pt_bubble, (rand()&3) + 12, bubbleparticletexture, lhrandom(1, 2), 255, 2, org, 16, 16); + { + for (i=0 ; i<128 ; i++) + particle2(pt_bubble, (rand()&3) + 12, bubbleparticletexture, lhrandom(1, 2), 255, 2, org, 16, 96); + } + else + { + for (i = 0;i < 256;i++) + particle(pt_fallfadespark, ramp3[rand()%6], particletexture, 1.5, lhrandom(128, 255), 5, lhrandom(-16, 16) + org[0], lhrandom(-16, 16) + org[1], lhrandom(-16, 16) + org[2], lhrandom(-192, 192), lhrandom(-192, 192), lhrandom(-192, 192) + 192); + } + } /* @@ -516,7 +508,7 @@ void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) if (!r_particles.value) return; // LordHavoc: particles are optional for (i = 0;i < 512;i++) - particle2(pt_fadespark2, colorStart + (i % colorLength), particletexture, 1.5, 255, 0.3, org, 8, 192); + particle2(pt_fade, colorStart + (i % colorLength), particletexture, 1.5, 255, 0.3, org, 8, 192); } /* @@ -573,17 +565,20 @@ void R_SparkShower (vec3_t org, vec3_t dir, int count) if (!r_particles.value) return; // LordHavoc: particles are optional // smoke puff - particle(pt_smokecloud, 12+(rand()&3), smokeparticletexture[rand()&7], 8, 64, 99, org[0], org[1], org[2], 0, 0, 0); + particle(pt_smoke, 12+(rand()&3), smokeparticletexture[rand()&7], 8, 160, 99, org[0], org[1], org[2], 0, 0, 0); // sparks while(count--) - particle2(pt_fallfadespark, ramp3[rand()%6], particletexture, 1, lhrandom(0, 255), 5, org, 4, 96); +// particle2(pt_fallfadespark, ramp3[rand()%6], particletexture, 1, lhrandom(0, 255), 5, org, 4, 96); + particle(pt_fallfadespark, ramp3[rand()%6], particletexture, 1, lhrandom(0, 255), 5, lhrandom(-4, 4) + org[0], lhrandom(-4, 4) + org[1], lhrandom(-4, 4) + org[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64) + 64); } void R_BloodPuff (vec3_t org) { if (!r_particles.value) return; // LordHavoc: particles are optional - particle(pt_bloodcloud, 68+(rand()&3), smokeparticletexture[rand()&7], 12, 128, 99, org[0], org[1], org[2], 0, 0, 0); + particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], 12, 128, 99, org[0], org[1], org[2], 0, 0, 0); + particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], 10, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 0, 0, 0); + particle(pt_bloodcloud, 251 /*68+(rand()&3)*/, smokeparticletexture[rand()&7], 8, 128, 99, org[0] + lhrandom(-4, 4), org[1] + lhrandom(-4, 4), org[2] + lhrandom(-4, 4), 0, 0, 0); } void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) @@ -599,20 +594,21 @@ void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count) center[0] = (mins[0] + maxs[0]) * 0.5; center[1] = (mins[1] + maxs[1]) * 0.5; center[2] = (mins[2] + maxs[2]) * 0.5; - velscale[0] = velspeed * 2.0 / diff[0]; - velscale[1] = velspeed * 2.0 / diff[1]; - velscale[2] = velspeed * 2.0 / diff[2]; + // FIXME: change velspeed back to 2.0x after fixing mod + velscale[0] = velspeed * 0.5 / diff[0]; + velscale[1] = velspeed * 0.5 / diff[1]; + velscale[2] = velspeed * 0.5 / diff[2]; while (count--) { ALLOCPARTICLE p->texnum = smokeparticletexture[rand()&7]; - p->scale = 12; + p->scale = lhrandom(4, 6); p->alpha = 96 + (rand()&63); p->die = cl.time + 2; - p->type = pt_fadespark; - p->color = (rand()&3)+68; + p->type = pt_bloodcloud; + p->color = 251; //(rand()&3)+68; for (j=0 ; j<3 ; j++) { p->org[j] = diff[j] * (float) (rand()%1024) * (1.0 / 1024.0) + mins[j]; @@ -697,18 +693,19 @@ 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 = 1.5; p->alpha = 255; p->die = t; if (type == 1) { + p->scale = 2; p->texnum = particletexture; p->type = pt_snow; } else // 0 { + p->scale = 3; p->texnum = rainparticletexture; - p->type = pt_static; + p->type = pt_rain; } p->color = colorbase + (rand()&3); VectorCopy(org, p->org); @@ -799,7 +796,6 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) 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 t = cl.oldtime; @@ -836,11 +832,11 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 1: // grenade trail if (bubbles) { - dec = 0.005f; + dec = type == 0 ? 0.01f : 0.02f; p->texnum = bubbleparticletexture; p->scale = lhrandom(1,2); p->alpha = 255; - p->color = (rand()&3)+12; + p->color = 254; p->type = pt_bubble; p->die = cl.time + 2; for (j=0 ; j<3 ; j++) @@ -851,14 +847,21 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) } else { - dec = 0.02f; + dec = type == 0 ? 0.01f : 0.02f; p->texnum = smokeparticletexture[rand()&7]; - p->scale = lhrandom(8, 12); - p->alpha = 64 + (rand()&31); - p->color = (rand()&3)+12; + p->scale = lhrandom(4, 8); + p->alpha = 160; //128 + (rand()&63); + p->color = 254; p->type = pt_smoke; p->die = cl.time + 10000; VectorCopy(start, p->org); + if (type == 0) + { + particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64)); + particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64)); + particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64)); + particle(pt_fallfadespark, 0x68 + (rand() & 7), particletexture, 1, lhrandom(64, 128), 5, start[0], start[1], start[2], lhrandom(-64, 64), lhrandom(-64, 64), lhrandom(-64, 64)); + } } break; @@ -879,11 +882,12 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) */ case 2: // blood + case 4: // slight blood dec = 0.025f; p->texnum = smokeparticletexture[rand()&7]; - p->scale = lhrandom(6, 8); - p->alpha = 255; - p->color = (rand()&3)+68; + p->scale = lhrandom(4, 6); + p->alpha = type == 4 ? 192 : 255; + p->color = 251; //(rand()&3)+68; p->type = pt_bloodcloud; p->die = cl.time + 9999; for (j=0 ; j<3 ; j++) @@ -895,45 +899,14 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) case 3: case 5: // tracer - dec = 0.01f; - p->texnum = particletexture; - p->scale = 2; - p->alpha = 255; - p->die = cl.time + 0.2; //5; - p->type = pt_static; - if (type == 3) - p->color = 52 + ((tracercount&4)<<1); - else - p->color = 230 + ((tracercount&4)<<1); - - tracercount++; - - VectorCopy (start, p->org); - if (tracercount & 1) - { - p->vel[0] = 30*vec[1]; - p->vel[1] = 30*-vec[0]; - } - else - { - p->vel[0] = 30*-vec[1]; - p->vel[1] = 30*vec[0]; - } - break; - - case 4: // slight blood - dec = 0.025f; // sparse trail + dec = 0.02f; 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 + 9999; - for (j=0 ; j<3 ; j++) - { - p->vel[j] = (rand()&15)-8; - p->org[j] = start[j] + ((rand()&3)-2); - } + p->scale = 4; + p->alpha = 64 + (rand()&31); + p->color = type == 3 ? 56 : 234; + p->type = pt_fade; + p->die = cl.time + 10000; + VectorCopy(start, p->org); break; case 6: // voor trail @@ -942,7 +915,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) p->scale = lhrandom(3, 5); p->alpha = 255; p->color = 9*16 + 8 + (rand()&3); - p->type = pt_fadespark2; + p->type = pt_fade; p->die = cl.time + 2; for (j=0 ; j<3 ; j++) { @@ -988,8 +961,6 @@ void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent) } -extern qboolean lighthalf; - /* =============== R_DrawParticles @@ -998,13 +969,15 @@ R_DrawParticles extern cvar_t sv_gravity; void R_CompleteLightPoint (vec3_t color, vec3_t p); +void TraceLine (vec3_t start, vec3_t end, vec3_t impact); + void R_DrawParticles (void) { particle_t *p; int i, r,g,b,a; float gravity, dvel, frametime, scale, scale2, minparticledist; byte *color24; - vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor; + vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor, v; int activeparticles, maxparticle, j, k; // LordHavoc: early out condition @@ -1072,6 +1045,7 @@ void R_DrawParticles (void) transpolyend(); } + VectorCopy(p->org, p->oldorg); p->org[0] += p->vel[0]*frametime; p->org[1] += p->vel[1]*frametime; p->org[2] += p->vel[2]*frametime; @@ -1094,13 +1068,6 @@ void R_DrawParticles (void) case pt_grav: p->vel[2] -= gravity; break; -// LordHavoc: for smoke trails - case pt_smoke: - p->scale += frametime * 6; - p->alpha -= frametime * 128; - if (p->alpha < 1) - p->die = -1; - break; case pt_snow: if (cl.time > p->time2) { @@ -1111,26 +1078,14 @@ void R_DrawParticles (void) } break; case pt_bloodcloud: - if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY) - { - p->die = -1; - break; - } - p->scale += frametime * 4; - p->alpha -= frametime * 64; - if (p->alpha < 1 || p->scale < 1) - p->die = -1; - break; - case pt_fadespark: - p->alpha -= frametime * 256; - p->vel[2] -= gravity; - if (p->alpha < 1) - p->die = -1; - break; - case pt_fadespark2: +// if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents != CONTENTS_EMPTY) +// { +// p->die = -1; +// break; +// } + p->scale += frametime * 16; p->alpha -= frametime * 512; - p->vel[2] -= gravity; - if (p->alpha < 1) + if (p->alpha < 1 || p->scale < 1) p->die = -1; break; case pt_fallfadespark: @@ -1139,39 +1094,97 @@ void R_DrawParticles (void) if (p->alpha < 1) p->die = -1; break; - case pt_fallfadespark2: - p->alpha -= frametime * 512; - p->vel[2] -= gravity; - 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: - if (Mod_PointInLeaf(p->org, cl.worldmodel)->contents == CONTENTS_EMPTY) - p->die = -1; - p->vel[2] += gravity; - if (p->vel[2] >= 200) - p->vel[2] = lhrandom(130, 200); + a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (a != CONTENTS_WATER && a != CONTENTS_SLIME) + { + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; + p->die = cl.time + 1000; +// p->die = -1; + } + p->vel[2] += gravity * 0.25; + p->vel[0] *= (1 - (frametime * 0.0625)); + p->vel[1] *= (1 - (frametime * 0.0625)); + p->vel[2] *= (1 - (frametime * 0.0625)); if (cl.time > p->time2) { p->time2 = cl.time + lhrandom(0, 0.5); - p->vel[0] = lhrandom(-32,32); - p->vel[1] = lhrandom(-32,32); + p->vel[0] += lhrandom(-32,32); + p->vel[1] += lhrandom(-32,32); + p->vel[2] += lhrandom(-32,32); } p->alpha -= frametime * 64; if (p->alpha < 1) p->die = -1; break; +// LordHavoc: for smoke trails + case pt_smoke: + p->vel[2] += gravity * 0.08f; + p->scale += frametime * 16; + p->alpha -= frametime * 384; + if (p->alpha < 16) + p->die = -1; + break; case pt_smokecloud: - p->scale += frametime * 60; - p->alpha -= frametime * 96; + p->scale += frametime * 64; + p->alpha -= frametime * 384; + if (p->alpha < 16) + p->die = -1; + break; + case pt_splash: + p->scale += frametime * 24; + p->alpha -= frametime * 512; if (p->alpha < 1) p->die = -1; break; + case pt_rain: + a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents; + if (a != CONTENTS_EMPTY && a != CONTENTS_SKY) + { + if (a == CONTENTS_SOLID && Mod_PointInLeaf(p->oldorg, cl.worldmodel)->contents == CONTENTS_SOLID) + break; // still in solid + p->die = cl.time + 1000; + switch (a) + { + case CONTENTS_LAVA: + case CONTENTS_SLIME: + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_smokecloud; + p->alpha = 64; + p->vel[2] = 96; + break; + case CONTENTS_WATER: + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; +// p->texnum = bubbleparticletexture; +// p->type = pt_bubble; +// p->vel[2] *= 0.1; + break; + default: // CONTENTS_SOLID and any others + TraceLine(p->oldorg, p->org, v); + VectorCopy(v, p->org); + p->texnum = smokeparticletexture[rand()&7]; + p->type = pt_splash; + p->alpha = 96; + p->scale = 5; + p->vel[0] = p->vel[1] = p->vel[2] = 0; + p->die = cl.time + 1000; + break; + } + } + break; } } // fill in gaps to compact the array