+void CL_ParseEffect2 (void)
+{
+ vec3_t org;
+ int modelindex, startframe, framecount, framerate;
+
+ MSG_ReadVector(org, cls.protocol);
+ modelindex = (unsigned short) MSG_ReadShort ();
+ startframe = (unsigned short) MSG_ReadShort ();
+ framecount = MSG_ReadByte ();
+ framerate = MSG_ReadByte ();
+
+ CL_Effect(org, modelindex, startframe, framecount, framerate);
+}
+
+void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning)
+{
+ int i;
+ beam_t *b = NULL;
+
+ if (ent >= MAX_EDICTS)
+ {
+ Con_Printf("CL_NewBeam: invalid entity number %i\n", ent);
+ ent = 0;
+ }
+
+ if (ent >= cl.max_entities)
+ CL_ExpandEntities(ent);
+
+ // override any beam with the same entity
+ i = cl.max_beams;
+ if (ent)
+ for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
+ if (b->entity == ent)
+ break;
+ // if the entity was not found then just replace an unused beam
+ if (i == cl.max_beams)
+ for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++)
+ if (!b->model)
+ break;
+ if (i < cl.max_beams)
+ {
+ cl.num_beams = max(cl.num_beams, i + 1);
+ b->entity = ent;
+ b->lightning = lightning;
+ b->model = m;
+ b->endtime = cl.mtime[0] + 0.2;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ }
+ else
+ Con_Print("beam list overflow!\n");
+}
+
+void CL_ParseBeam (dp_model_t *m, int lightning)
+{
+ int ent;
+ vec3_t start, end;
+
+ ent = (unsigned short) MSG_ReadShort ();
+ MSG_ReadVector(start, cls.protocol);
+ MSG_ReadVector(end, cls.protocol);
+
+ if (ent >= MAX_EDICTS)
+ {
+ Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent);
+ ent = 0;
+ }
+
+ CL_NewBeam(ent, start, end, m, lightning);
+}
+
+void CL_ParseTempEntity(void)
+{
+ int type;
+ vec3_t pos, pos2;
+ vec3_t vel1, vel2;
+ vec3_t dir;
+ vec3_t color;
+ int rnd;
+ int colorStart, colorLength, count;
+ float velspeed, radius;
+ unsigned char *tempcolor;
+ matrix4x4_t tempmatrix;
+
+ if (cls.protocol == PROTOCOL_QUAKEWORLD)
+ {
+ type = MSG_ReadByte();
+ switch (type)
+ {
+ case QW_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 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, NULL), 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 = palette_rgb[(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, 1, 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);
+}
+
+void CL_ParsePointParticles1(void)
+{
+ int effectindex;
+ vec3_t origin;
+ effectindex = (unsigned short)MSG_ReadShort();
+ MSG_ReadVector(origin, cls.protocol);
+ CL_ParticleEffect(effectindex, 1, origin, origin, vec3_origin, vec3_origin, 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_extra.integer)
+ Con_DPrintf("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_extra.integer)
+ Con_DPrintf("... 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 = (cl_iplog_item_t *) 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 = (char *) Mem_Alloc(cls.permanentmempool, strlen(address) + 1);
+ cl_iplog_items[cl_iplog_numitems].name = (char *) 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_extra.integer)
+ Con_DPrintf("CL_IPLog_Add: appending this line to %s: %s %s\n", cl_iplog_name.string, address, name);
+ }
+}
+
+static void CL_IPLog_Load(void)