+/*
+===============
+CL_EntityParticles
+===============
+*/
+void CL_EntityParticles (const entity_t *ent)
+{
+ int i;
+ float pitch, yaw, dist = 64, beamlength = 16, org[3], v[3];
+ static vec3_t avelocities[NUMVERTEXNORMALS];
+ if (!cl_particles.integer) return;
+
+ Matrix4x4_OriginFromMatrix(&ent->render.matrix, org);
+
+ if (!avelocities[0][0])
+ for (i = 0;i < NUMVERTEXNORMALS * 3;i++)
+ avelocities[0][i] = lhrandom(0, 2.55);
+
+ for (i = 0;i < NUMVERTEXNORMALS;i++)
+ {
+ yaw = cl.time * avelocities[i][0];
+ pitch = cl.time * avelocities[i][1];
+ v[0] = org[0] + m_bytenormals[i][0] * dist + (cos(pitch)*cos(yaw)) * beamlength;
+ v[1] = org[1] + m_bytenormals[i][1] * dist + (cos(pitch)*sin(yaw)) * beamlength;
+ v[2] = org[2] + m_bytenormals[i][2] * dist + (-sin(pitch)) * beamlength;
+ particle(particletype + pt_entityparticle, particlepalette[0x6f], particlepalette[0x6f], tex_particle, 1, 0, 255, 0, 0, 0, v[0], v[1], v[2], 0, 0, 0, 0, 0, 0, 0);
+ }
+}
+
+
+void CL_ReadPointFile_f (void)
+{
+ vec3_t org, leakorg;
+ int r, c, s;
+ char *pointfile = NULL, *pointfilepos, *t, tchar;
+ char name[MAX_OSPATH];
+
+ if (!cl.worldmodel)
+ return;
+
+ FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
+ strlcat (name, ".pts", sizeof (name));
+ pointfile = (char *)FS_LoadFile(name, tempmempool, true, NULL);
+ if (!pointfile)
+ {
+ Con_Printf("Could not open %s\n", name);
+ return;
+ }
+
+ Con_Printf("Reading %s...\n", name);
+ VectorClear(leakorg);
+ c = 0;
+ s = 0;
+ pointfilepos = pointfile;
+ while (*pointfilepos)
+ {
+ while (*pointfilepos == '\n' || *pointfilepos == '\r')
+ pointfilepos++;
+ if (!*pointfilepos)
+ break;
+ t = pointfilepos;
+ while (*t && *t != '\n' && *t != '\r')
+ t++;
+ tchar = *t;
+ *t = 0;
+ r = sscanf (pointfilepos,"%f %f %f", &org[0], &org[1], &org[2]);
+ *t = tchar;
+ pointfilepos = t;
+ if (r != 3)
+ break;
+ if (c == 0)
+ VectorCopy(org, leakorg);
+ c++;
+
+ if (cl.num_particles < cl.max_particles - 3)
+ {
+ s++;
+ particle(particletype + pt_static, particlepalette[(-c)&15], particlepalette[(-c)&15], tex_particle, 2, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0);
+ }
+ }
+ Mem_Free(pointfile);
+ VectorCopy(leakorg, org);
+ Con_Printf("%i points read (%i particles spawned)\nLeak at %f %f %f\n", c, s, org[0], org[1], org[2]);
+
+ particle(particletype + pt_beam, 0xFF0000, 0xFF0000, tex_beam, 64, 0, 255, 0, 0, 0, org[0] - 4096, org[1], org[2], org[0] + 4096, org[1], org[2], 0, 0, 0, 0);
+ particle(particletype + pt_beam, 0x00FF00, 0x00FF00, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1] - 4096, org[2], org[0], org[1] + 4096, org[2], 0, 0, 0, 0);
+ particle(particletype + pt_beam, 0x0000FF, 0x0000FF, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1], org[2] - 4096, org[0], org[1], org[2] + 4096, 0, 0, 0, 0);
+}
+
+/*
+===============
+CL_ParseParticleEffect
+
+Parse an effect out of the server message
+===============
+*/
+void CL_ParseParticleEffect (void)
+{
+ vec3_t org, dir;
+ int i, count, msgcount, color;
+
+ MSG_ReadVector(org, cls.protocol);
+ for (i=0 ; i<3 ; i++)
+ dir[i] = MSG_ReadChar ();
+ msgcount = MSG_ReadByte ();
+ color = MSG_ReadByte ();
+
+ if (msgcount == 255)
+ count = 1024;
+ else
+ count = msgcount;
+
+ CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
+}
+
+/*
+===============
+CL_ParticleExplosion
+
+===============
+*/
+void CL_ParticleExplosion (const vec3_t org)
+{
+ int i;
+ trace_t trace;
+ //vec3_t v;
+ //vec3_t v2;
+ if (cl_stainmaps.integer)
+ R_Stain(org, 96, 80, 80, 80, 64, 176, 176, 176, 64);
+ CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF);
+
+ if (cl_particles_quake.integer)
+ {
+ for (i = 0;i < 1024;i++)
+ {
+ int r, color;
+ r = rand()&3;
+ if (i & 1)
+ {
+ color = particlepalette[ramp1[r]];
+ particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 32 * (8 - r), 318, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256);
+ }
+ else
+ {
+ color = particlepalette[ramp2[r]];
+ particle(particletype + pt_alphastatic, color, color, tex_particle, 1, 0, 32 * (8 - r), 478, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256);
+ }
+ }
+ }
+ else
+ {
+ i = CL_PointSuperContents(org);
+ if (i & (SUPERCONTENTS_SLIME | SUPERCONTENTS_WATER))
+ {
+ if (cl_particles.integer && cl_particles_bubbles.integer)
+ for (i = 0;i < 128 * cl_particles_quality.value;i++)
+ particle(particletype + pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 255), 128, -0.125, 1.5, org[0], org[1], org[2], 0, 0, 0, 0.0625, 0.25, 16, 96);
+ }
+ else
+ {
+ // LordHavoc: smoke effect similar to UT2003, chews fillrate too badly up close
+ // smoke puff
+ if (cl_particles.integer && cl_particles_smoke.integer && cl_particles_explosions_smoke.integer)
+ {
+ for (i = 0;i < 32;i++)
+ {
+ int k;
+ vec3_t v, v2;
+ for (k = 0;k < 16;k++)
+ {
+ v[0] = org[0] + lhrandom(-48, 48);
+ v[1] = org[1] + lhrandom(-48, 48);
+ v[2] = org[2] + lhrandom(-48, 48);
+ trace = CL_TraceBox(org, vec3_origin, vec3_origin, v, true, NULL, SUPERCONTENTS_SOLID, false);
+ if (trace.fraction >= 0.1)
+ break;
+ }
+ VectorSubtract(trace.endpos, org, v2);
+ VectorScale(v2, 2.0f, v2);
+ particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 0, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0);
+ }
+ }
+
+ if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer)
+ for (i = 0;i < 128 * cl_particles_quality.value;i++)
+ particle(particletype + pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 1, 0, org[0], org[1], org[2], 0, 0, 80, 0.2, 0.8, 0, 256);
+ }
+ }
+
+ if (cl_particles_explosions_shell.integer)
+ R_NewExplosion(org);
+}
+
+/*
+===============
+CL_ParticleExplosion2
+
+===============
+*/
+void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength)
+{
+ int i, k;
+ if (!cl_particles.integer) return;
+
+ for (i = 0;i < 512 * cl_particles_quality.value;i++)
+ {
+ k = particlepalette[colorStart + (i % colorLength)];
+ if (cl_particles_quake.integer)
+ particle(particletype + pt_static, k, k, tex_particle, 1, 0, 255, 850, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 8, 256);
+ else
+ particle(particletype + pt_static, k, k, tex_particle, lhrandom(0.5, 1.5), 0, 255, 512, 0, 0, org[0], org[1], org[2], 0, 0, 0, lhrandom(1.5, 3), lhrandom(1.5, 3), 8, 192);