+ case QW_TE_KNIGHTSPIKE:
+ // spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1);
+ break;
+
+ case QW_TE_SPIKE:
+ // spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+ case QW_TE_SUPERSPIKE:
+ // super spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+
+ case QW_TE_EXPLOSION:
+ // rocket explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ CL_Effect(pos, cl.qw_modelindex_s_explod, 0, 6, 10);
+ break;
+
+ case QW_TE_TAREXPLOSION:
+ // tarbaby explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case QW_TE_LIGHTNING1:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt, true);
+ break;
+
+ case QW_TE_LIGHTNING2:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt2, true);
+ break;
+
+ case QW_TE_LIGHTNING3:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt3, false);
+ break;
+
+ case QW_TE_LAVASPLASH:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case QW_TE_TELEPORT:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case QW_TE_GUNSHOT:
+ // bullet hitting wall
+ radius = MSG_ReadByte();
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ VectorSet(pos2, pos[0] + radius, pos[1] + radius, pos[2] + radius);
+ VectorSet(pos, pos[0] - radius, pos[1] - radius, pos[2] - radius);
+ CL_ParticleEffect(EFFECT_TE_GUNSHOT, radius, pos, pos2, vec3_origin, vec3_origin, NULL, 0);
+ if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT)
+ {
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ }
+ break;
+
+ case QW_TE_BLOOD:
+ count = MSG_ReadByte();
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case QW_TE_LIGHTNINGBLOOD:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_BLOOD, 2.5, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ default:
+ Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
+ }
+ }
+ else
+ {
+ type = MSG_ReadByte();
+ switch (type)
+ {
+ case TE_WIZSPIKE:
+ // spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1);
+ break;
+
+ case TE_KNIGHTSPIKE:
+ // spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1);
+ break;
+
+ case TE_SPIKE:
+ // spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+ case TE_SPIKEQUAD:
+ // quad spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+ case TE_SUPERSPIKE:
+ // super spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+ case TE_SUPERSPIKEQUAD:
+ // quad super spike hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ break;
+ // LordHavoc: added for improved blood splatters
+ case TE_BLOOD:
+ // blood puff
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ dir[0] = MSG_ReadChar();
+ dir[1] = MSG_ReadChar();
+ dir[2] = MSG_ReadChar();
+ count = MSG_ReadByte();
+ CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, dir, dir, NULL, 0);
+ break;
+ case TE_SPARK:
+ // spark shower
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ dir[0] = MSG_ReadChar();
+ dir[1] = MSG_ReadChar();
+ dir[2] = MSG_ReadChar();
+ count = MSG_ReadByte();
+ CL_ParticleEffect(EFFECT_TE_SPARK, count, pos, pos, dir, dir, NULL, 0);
+ break;
+ case TE_PLASMABURN:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+ // LordHavoc: added for improved gore
+ case TE_BLOODSHOWER:
+ // vaporized body
+ MSG_ReadVector(pos, cls.protocol); // mins
+ MSG_ReadVector(pos2, cls.protocol); // maxs
+ velspeed = MSG_ReadCoord(cls.protocol); // speed
+ count = (unsigned short) MSG_ReadShort(); // number of particles
+ vel1[0] = -velspeed;
+ vel1[1] = -velspeed;
+ vel1[2] = -velspeed;
+ vel2[0] = velspeed;
+ vel2[1] = velspeed;
+ vel2[2] = velspeed;
+ CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos2, vel1, vel2, NULL, 0);
+ break;
+
+ case TE_PARTICLECUBE:
+ // general purpose particle effect
+ MSG_ReadVector(pos, cls.protocol); // mins
+ MSG_ReadVector(pos2, cls.protocol); // maxs
+ MSG_ReadVector(dir, cls.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
+ colorStart = MSG_ReadByte(); // color
+ colorLength = MSG_ReadByte(); // gravity (1 or 0)
+ velspeed = MSG_ReadCoord(cls.protocol); // randomvel
+ CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength != 0, velspeed);
+ break;
+
+ case TE_PARTICLERAIN:
+ // general purpose particle effect
+ MSG_ReadVector(pos, cls.protocol); // mins
+ MSG_ReadVector(pos2, cls.protocol); // maxs
+ MSG_ReadVector(dir, cls.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
+ colorStart = MSG_ReadByte(); // color
+ CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
+ break;
+
+ case TE_PARTICLESNOW:
+ // general purpose particle effect
+ MSG_ReadVector(pos, cls.protocol); // mins
+ MSG_ReadVector(pos2, cls.protocol); // maxs
+ MSG_ReadVector(dir, cls.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
+ colorStart = MSG_ReadByte(); // color
+ CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
+ break;
+
+ case TE_GUNSHOT:
+ // bullet hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT)
+ {
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ }
+ break;
+
+ case TE_GUNSHOTQUAD:
+ // quad bullet hitting wall
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ if(cl_sound_ric_gunshot.integer & RIC_GUNSHOTQUAD)
+ {
+ if (rand() % 5)
+ S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
+ else
+ {
+ rnd = rand() & 3;
+ if (rnd == 1)
+ S_StartSound(-1, 0, cl.sfx_ric1, pos, 1, 1);
+ else if (rnd == 2)
+ S_StartSound(-1, 0, cl.sfx_ric2, pos, 1, 1);
+ else
+ S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1);
+ }
+ }
+ break;
+
+ case TE_EXPLOSION:
+ // rocket explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_EXPLOSIONQUAD:
+ // quad rocket explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_EXPLOSION3:
+ // Nehahra movie colored lighting explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ color[0] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
+ color[1] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
+ color[2] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
+ CL_ParticleExplosion(pos);
+ Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
+ CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_EXPLOSIONRGB:
+ // colored lighting explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleExplosion(pos);
+ color[0] = MSG_ReadByte() * (2.0f / 255.0f);
+ color[1] = MSG_ReadByte() * (2.0f / 255.0f);
+ color[2] = MSG_ReadByte() * (2.0f / 255.0f);
+ Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
+ CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_TAREXPLOSION:
+ // tarbaby explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_SMALLFLASH:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case TE_CUSTOMFLASH:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 4);
+ radius = (MSG_ReadByte() + 1) * 8;
+ velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
+ color[0] = MSG_ReadByte() * (2.0f / 255.0f);
+ color[1] = MSG_ReadByte() * (2.0f / 255.0f);
+ color[2] = MSG_ReadByte() * (2.0f / 255.0f);
+ Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
+ CL_AllocLightFlash(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ break;
+
+ case TE_FLAMEJET:
+ MSG_ReadVector(pos, cls.protocol);
+ MSG_ReadVector(dir, cls.protocol);
+ count = MSG_ReadByte();
+ CL_ParticleEffect(EFFECT_TE_FLAMEJET, count, pos, pos, dir, dir, NULL, 0);
+ break;
+
+ case TE_LIGHTNING1:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt, true);
+ break;
+
+ case TE_LIGHTNING2:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt2, true);
+ break;
+
+ case TE_LIGHTNING3:
+ // lightning bolts
+ CL_ParseBeam(cl.model_bolt3, false);
+ break;
+
+ // PGM 01/21/97
+ case TE_BEAM:
+ // grappling hook beam
+ CL_ParseBeam(cl.model_beam, false);
+ break;
+ // PGM 01/21/97
+
+ // LordHavoc: for compatibility with the Nehahra movie...
+ case TE_LIGHTNING4NEH:
+ CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, false), false);
+ break;
+
+ case TE_LAVASPLASH:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case TE_TELEPORT:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case TE_EXPLOSION2:
+ // color mapped explosion
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ colorStart = MSG_ReadByte();
+ colorLength = MSG_ReadByte();
+ CL_ParticleExplosion2(pos, colorStart, colorLength);
+ tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
+ color[0] = tempcolor[0] * (2.0f / 255.0f);
+ color[1] = tempcolor[1] * (2.0f / 255.0f);
+ color[2] = tempcolor[2] * (2.0f / 255.0f);
+ Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
+ CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_TEI_G3:
+ MSG_ReadVector(pos, cls.protocol);
+ MSG_ReadVector(pos2, cls.protocol);
+ MSG_ReadVector(dir, cls.protocol);
+ CL_ParticleEffect(EFFECT_TE_TEI_G3, 1, pos, pos2, dir, dir, NULL, 0);
+ break;
+
+ case TE_TEI_SMOKE:
+ MSG_ReadVector(pos, cls.protocol);
+ MSG_ReadVector(dir, cls.protocol);
+ count = MSG_ReadByte();
+ CL_FindNonSolidLocation(pos, pos, 4);
+ CL_ParticleEffect(EFFECT_TE_TEI_SMOKE, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ case TE_TEI_BIGEXPLOSION:
+ MSG_ReadVector(pos, cls.protocol);
+ CL_FindNonSolidLocation(pos, pos, 10);
+ CL_ParticleEffect(EFFECT_TE_TEI_BIGEXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1);
+ break;
+
+ case TE_TEI_PLASMAHIT:
+ MSG_ReadVector(pos, cls.protocol);
+ MSG_ReadVector(dir, cls.protocol);
+ count = MSG_ReadByte();
+ CL_FindNonSolidLocation(pos, pos, 5);
+ CL_ParticleEffect(EFFECT_TE_TEI_PLASMAHIT, count, pos, pos, vec3_origin, vec3_origin, NULL, 0);
+ break;
+
+ default:
+ Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type);
+ }
+ }
+}
+
+void CL_ParseTrailParticles(void)
+{
+ int entityindex;
+ int effectindex;
+ vec3_t start, end;
+ entityindex = (unsigned short)MSG_ReadShort();
+ if (entityindex >= MAX_EDICTS)
+ entityindex = 0;
+ if (entityindex >= cl.max_entities)
+ CL_ExpandEntities(entityindex);
+ effectindex = (unsigned short)MSG_ReadShort();
+ MSG_ReadVector(start, cls.protocol);
+ MSG_ReadVector(end, cls.protocol);
+ CL_ParticleEffect(effectindex, VectorDistance(start, end), start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0);
+}
+
+void CL_ParsePointParticles(void)
+{
+ int effectindex, count;
+ vec3_t origin, velocity;
+ effectindex = (unsigned short)MSG_ReadShort();
+ MSG_ReadVector(origin, cls.protocol);
+ MSG_ReadVector(velocity, cls.protocol);
+ count = (unsigned short)MSG_ReadShort();
+ CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0);
+}
+
+typedef struct cl_iplog_item_s
+{
+ char *address;
+ char *name;
+}
+cl_iplog_item_t;
+
+static qboolean cl_iplog_loaded = false;
+static int cl_iplog_numitems = 0;
+static int cl_iplog_maxitems = 0;
+static cl_iplog_item_t *cl_iplog_items;
+
+static void CL_IPLog_Load(void);
+static void CL_IPLog_Add(const char *address, const char *name, qboolean checkexisting, qboolean addtofile)
+{
+ int i;
+ if (!address || !address[0] || !name || !name[0])
+ return;
+ if (!cl_iplog_loaded)
+ CL_IPLog_Load();
+ if (developer.integer >= 100)
+ Con_Printf("CL_IPLog_Add(\"%s\", \"%s\", %i, %i);\n", address, name, checkexisting, addtofile);
+ // see if it already exists
+ if (checkexisting)
+ {
+ for (i = 0;i < cl_iplog_numitems;i++)
+ {
+ if (!strcmp(cl_iplog_items[i].address, address) && !strcmp(cl_iplog_items[i].name, name))
+ {
+ if (developer.integer >= 100)
+ Con_Printf("... found existing \"%s\" \"%s\"\n", cl_iplog_items[i].address, cl_iplog_items[i].name);
+ return;
+ }
+ }
+ }
+ // it does not already exist in the iplog, so add it
+ if (cl_iplog_maxitems <= cl_iplog_numitems || !cl_iplog_items)
+ {
+ cl_iplog_item_t *olditems = cl_iplog_items;
+ cl_iplog_maxitems = max(1024, cl_iplog_maxitems + 256);
+ cl_iplog_items = Mem_Alloc(cls.permanentmempool, cl_iplog_maxitems * sizeof(cl_iplog_item_t));
+ if (olditems)
+ {
+ if (cl_iplog_numitems)
+ memcpy(cl_iplog_items, olditems, cl_iplog_numitems * sizeof(cl_iplog_item_t));
+ Mem_Free(olditems);
+ }
+ }
+ cl_iplog_items[cl_iplog_numitems].address = Mem_Alloc(cls.permanentmempool, strlen(address) + 1);
+ cl_iplog_items[cl_iplog_numitems].name = Mem_Alloc(cls.permanentmempool, strlen(name) + 1);
+ strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, strlen(address) + 1);
+ // TODO: maybe it would be better to strip weird characters from name when
+ // copying it here rather than using a straight strcpy?
+ strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, strlen(name) + 1);
+ cl_iplog_numitems++;
+ if (addtofile)
+ {
+ // add it to the iplog.txt file
+ // TODO: this ought to open the one in the userpath version of the base
+ // gamedir, not the current gamedir
+ Log_Printf(cl_iplog_name.string, "%s %s\n", address, name);
+ if (developer.integer >= 100)
+ Con_Printf("CL_IPLog_Add: appending this line to %s: %s %s\n", cl_iplog_name.string, address, name);
+ }
+}
+
+static void CL_IPLog_Load(void)
+{
+ int i, len, linenumber;
+ char *text, *textend;
+ unsigned char *filedata;
+ fs_offset_t filesize;
+ char line[MAX_INPUTLINE];
+ char address[MAX_INPUTLINE];
+ cl_iplog_loaded = true;
+ // TODO: this ought to open the one in the userpath version of the base
+ // gamedir, not the current gamedir
+ filedata = FS_LoadFile(cl_iplog_name.string, tempmempool, true, &filesize);
+ if (!filedata)
+ return;
+ text = (char *)filedata;
+ textend = text + filesize;
+ for (linenumber = 1;text < textend;linenumber++)
+ {
+ for (len = 0;text < textend && *text != '\r' && *text != '\n';text++)
+ if (len < (int)sizeof(line) - 1)
+ line[len++] = *text;
+ line[len] = 0;
+ if (text < textend && *text == '\r' && text[1] == '\n')
+ text++;
+ if (text < textend && *text == '\n')
+ text++;
+ if (line[0] == '/' && line[1] == '/')
+ continue; // skip comments if anyone happens to add them
+ for (i = 0;i < len && line[i] > ' ';i++)
+ address[i] = line[i];
+ address[i] = 0;
+ // skip exactly one space character
+ i++;
+ // address contains the address with termination,
+ // line + i contains the name with termination
+ if (address[0] && line[i])
+ CL_IPLog_Add(address, line + i, false, false);
+ else
+ Con_Printf("%s:%i: could not parse address and name:\n%s\n", cl_iplog_name.string, linenumber, line);
+ }
+}