#define PARTICLEEFFECT_UNDERWATER 1
#define PARTICLEEFFECT_NOTUNDERWATER 2
+#define PARTICLEEFFECT_DEFINED 2147483648U
typedef struct particleeffectinfo_s
{
{
int arrayindex;
int argc;
+ int i;
int linenumber;
particleeffectinfo_t *info = NULL;
const char *text = textstart;
Con_Printf("%s:%i: too many effects!\n", filename, linenumber);
break;
}
+ for(i = 0; i < numparticleeffectinfo; ++i)
+ {
+ info = particleeffectinfo + i;
+ if(!(info->flags & PARTICLEEFFECT_DEFINED))
+ if(info->effectnameindex == effectnameindex)
+ break;
+ }
+ if(i < numparticleeffectinfo)
+ continue;
info = particleeffectinfo + numparticleeffectinfo++;
// copy entire info from baseline, then fix up the nameindex
*info = baselineparticleeffectinfo;
info->effectnameindex = effectnameindex;
+ continue;
}
else if (info == NULL)
{
Con_Printf("%s:%i: command %s encountered before effect\n", filename, linenumber, argv[0]);
break;
}
- else if (!strcmp(argv[0], "countabsolute")) {readfloat(info->countabsolute);}
+
+ info->flags |= PARTICLEEFFECT_DEFINED;
+ if (!strcmp(argv[0], "countabsolute")) {readfloat(info->countabsolute);}
else if (!strcmp(argv[0], "count")) {readfloat(info->countmultiplier);}
else if (!strcmp(argv[0], "type"))
{
part->typeindex = pt_spark;
part->bounce = 0;
VectorMA(part->org, lifetime, part->vel, endvec);
- trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false, false);
+ trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, collision_extendmovelength.value, true, false, NULL, false, false);
part->die = cl.time + lifetime * trace.fraction;
part2 = CL_NewParticle(endvec, pt_raindecal, pcolor1, pcolor2, tex_rainsplash, part->size, part->size * 20, part->alpha, part->alpha / 0.4, 0, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2], 0, 0, 0, 0, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, -1, -1, -1, 1, 1, 0, 0, NULL);
if (part2)
{
VectorRandom(org2);
VectorMA(org, maxdist, org2, org2);
- trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false, true);
+ trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, &hitent, false, true);
// take the closest trace result that doesn't end up hitting a NOMARKS
// surface (sky for example)
if (bestfrac > trace.fraction && !(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS))
static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount);
static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount);
-static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles)
+static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail);
+static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, qboolean wanttrail)
{
vec3_t center;
matrix4x4_t tempmatrix;
{
// bloodhack checks if this effect's color matches regular or lightning blood and if so spawns a blood effect instead
if (count == 1024)
- CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else if (cl_particles_blood_bloodhack.integer && !cl_particles_quake.integer && (palettecolor == 73 || palettecolor == 225))
- CL_ParticleEffect(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else
{
count *= cl_particles_quality.value;
}
}
else if (effectnameindex == EFFECT_TE_WIZSPIKE)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 30*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 20);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 30*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 20, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else if (effectnameindex == EFFECT_TE_KNIGHTSPIKE)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 226);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 226, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else if (effectnameindex == EFFECT_TE_SPIKE)
{
if (cl_particles_bulletimpacts.integer)
if (cl_particles_quake.integer)
{
if (cl_particles_smoke.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
}
else
{
if (cl_particles_quake.integer)
{
if (cl_particles_smoke.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
}
else
{
if (cl_particles_quake.integer)
{
if (cl_particles_smoke.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
}
else
{
if (cl_particles_quake.integer)
{
if (cl_particles_smoke.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
}
else
{
if (!cl_particles_blood.integer)
return;
if (cl_particles_quake.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 2*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 73);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 2*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 73, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else
{
static double bloodaccumulator = 0;
if (cl_particles_bulletimpacts.integer)
{
if (cl_particles_quake.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else
{
CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count);
if (cl_particles_bulletimpacts.integer)
{
if (cl_particles_quake.integer)
- CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0);
+ CL_NewParticlesFromEffectinfo(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0, spawndlight, spawnparticles, NULL, NULL, 1, wanttrail);
else
{
CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count);
// this is also called on point effects with spawndlight = true and
// spawnparticles = true
-// it is called CL_ParticleTrail because most code does not want to supply
-// these parameters, only trail handling does
static void CL_NewParticlesFromEffectinfo(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade, qboolean wanttrail)
{
qboolean found = false;
}
for (effectinfoindex = 0, info = particleeffectinfo;effectinfoindex < MAX_PARTICLEEFFECTINFO && info->effectnameindex;effectinfoindex++, info++)
{
- if (info->effectnameindex == effectnameindex)
+ if ((info->effectnameindex == effectnameindex) && (info->flags & PARTICLEEFFECT_DEFINED))
{
qboolean definedastrail = info->trailspacing > 0;
if ((info->flags & PARTICLEEFFECT_NOTUNDERWATER) && underwater)
continue;
- // trail effects may only ever be drawn as trail
- if (!drawastrail && definedastrail)
- continue;
-
// spawn a dlight if requested
if (info->lightradiusstart > 0 && spawndlight)
{
}
else if (info->orientation == PARTICLE_HBEAM)
{
+ if (!drawastrail)
+ continue;
+
AnglesFromVectors(angles, traildir, NULL, false);
AngleVectors(angles, forward, right, up);
VectorMAMAM(info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos);
}
else
{
+ float cnt;
if (!cl_particles.integer)
continue;
switch (info->particletype)
case pt_snow: if (!cl_particles_snow.integer) continue;break;
default: break;
}
- VectorCopy(originmins, trailpos);
+
+ cnt = info->countabsolute;
+ cnt += (pcount * info->countmultiplier) * cl_particles_quality.value;
+ // if drawastrail is not set, we will
+ // use the regular cnt-based random
+ // particle spawning at the center; so
+ // do NOT apply trailspacing then!
+ if (drawastrail && definedastrail)
+ cnt += (traillen / info->trailspacing) * cl_particles_quality.value;
+ cnt *= fade;
+ if (cnt == 0)
+ continue; // nothing to draw
+ info->particleaccumulator += cnt;
+
+ if (drawastrail || definedastrail)
+ immediatebloodstain = false;
+ else
+ immediatebloodstain =
+ ((cl_decals_newsystem_immediatebloodstain.integer >= 1) && (info->particletype == pt_blood))
+ ||
+ ((cl_decals_newsystem_immediatebloodstain.integer >= 2) && staintex);
+
if (drawastrail)
{
- float cnt = info->countabsolute;
- cnt += (pcount * info->countmultiplier) * cl_particles_quality.value;
- if (info->trailspacing > 0)
- cnt += (traillen / info->trailspacing) * cl_particles_quality.value;
- cnt *= fade;
- info->particleaccumulator += cnt;
+ VectorCopy(originmins, trailpos);
trailstep = traillen / cnt;
- immediatebloodstain = false;
-
- AnglesFromVectors(angles, traildir, NULL, false);
}
else
{
- float cnt = info->countabsolute;
- cnt += (pcount * info->countmultiplier) * cl_particles_quality.value;
- cnt *= fade;
- info->particleaccumulator += cnt;
+ VectorCopy(center, trailpos);
trailstep = 0;
- immediatebloodstain =
- ((cl_decals_newsystem_immediatebloodstain.integer >= 1) && (info->particletype == pt_blood))
- ||
- ((cl_decals_newsystem_immediatebloodstain.integer >= 2) && staintex);
+ }
+ if (trailstep == 0)
+ {
VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity);
AnglesFromVectors(angles, velocity, NULL, false);
}
+ else
+ AnglesFromVectors(angles, traildir, NULL, false);
+
AngleVectors(angles, forward, right, up);
VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos);
VectorMAMAM(info->relativevelocityoffset[0], forward, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity);
tex = (int)lhrandom(info->tex[0], info->tex[1]);
tex = min(tex, info->tex[1] - 1);
}
- if (!trailstep)
+ if (!(drawastrail || definedastrail))
{
trailpos[0] = lhrandom(originmins[0], originmaxs[0]);
trailpos[1] = lhrandom(originmins[1], originmaxs[1]);
}
}
if (!found)
- CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles);
+ CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, wanttrail);
}
void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4], float fade)
CL_NewParticlesFromEffectinfo(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles, tintmins, tintmaxs, fade, false);
}
+// note: this one ONLY does boxes!
void CL_ParticleEffect(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor)
{
CL_ParticleBox(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, true, true, NULL, NULL, 1);
{
VectorRandom(v2);
VectorMA(org, 128, v2, v);
- trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false);
+ trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, false);
}
while (k < 16 && trace.fraction < 0.1f);
VectorSubtract(trace.endpos, org, v2);
// if (p->bounce && cl.time >= p->delayedcollisions)
if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel))
{
- trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false, false);
+ trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), collision_extendmovelength.value, true, false, &hitent, false, false);
// if the trace started in or hit something of SUPERCONTENTS_NODROP
// or if the trace hit something flagged as NOIMPACT
// then remove the particle