2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // cl_tent.c -- client side temporary entities
24 model_t *cl_model_bolt = NULL;
25 model_t *cl_model_bolt2 = NULL;
26 model_t *cl_model_bolt3 = NULL;
27 model_t *cl_model_beam = NULL;
30 sfx_t *cl_sfx_knighthit;
42 void CL_InitTEnts (void)
44 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav", false);
45 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav", false);
46 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav", false);
47 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav", false);
48 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav", false);
49 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav", false);
50 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav", false);
58 void CL_ParseBeam (model_t *m)
64 ent = MSG_ReadShort ();
65 MSG_ReadVector(start);
68 // override any beam with the same entity
69 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
75 b->endtime = cl.time + 0.2;
76 VectorCopy (start, b->start);
77 VectorCopy (end, b->end);
83 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
85 if (!b->model || b->endtime < cl.time)
89 b->endtime = cl.time + 0.2;
90 VectorCopy (start, b->start);
91 VectorCopy (end, b->end);
95 Con_Printf ("beam list overflow!\n");
104 void CL_ParseTEnt (void)
112 int colorStart, colorLength, count;
113 float velspeed, radius;
116 type = MSG_ReadByte ();
120 // spike hitting wall
122 Mod_FindNonSolidLocation(pos, cl.worldmodel);
123 CL_RunParticleEffect (pos, vec3_origin, 20, 30);
124 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
128 // spike hitting wall
130 Mod_FindNonSolidLocation(pos, cl.worldmodel);
131 CL_RunParticleEffect (pos, vec3_origin, 226, 20);
132 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
136 // spike hitting wall
138 Mod_FindNonSolidLocation(pos, cl.worldmodel);
139 // LordHavoc: changed to spark shower
140 CL_SparkShower(pos, vec3_origin, 15);
142 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
147 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
149 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
151 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
155 // quad spike hitting wall
157 Mod_FindNonSolidLocation(pos, cl.worldmodel);
158 // LordHavoc: changed to spark shower
159 CL_SparkShower(pos, vec3_origin, 15);
160 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
161 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
163 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
168 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
170 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
172 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
176 // super spike hitting wall
178 Mod_FindNonSolidLocation(pos, cl.worldmodel);
179 // LordHavoc: changed to dust shower
180 CL_SparkShower(pos, vec3_origin, 30);
182 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
187 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
189 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
191 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
194 case TE_SUPERSPIKEQUAD:
195 // quad super spike hitting wall
197 Mod_FindNonSolidLocation(pos, cl.worldmodel);
198 // LordHavoc: changed to dust shower
199 CL_SparkShower(pos, vec3_origin, 30);
200 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
202 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
207 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
209 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
211 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
214 // LordHavoc: added for improved blood splatters
218 dir[0] = MSG_ReadChar ();
219 dir[1] = MSG_ReadChar ();
220 dir[2] = MSG_ReadChar ();
221 count = MSG_ReadByte ();
222 CL_BloodPuff(pos, dir, count);
227 CL_BloodPuff(pos, vec3_origin, 10);
232 dir[0] = MSG_ReadChar ();
233 dir[1] = MSG_ReadChar ();
234 dir[2] = MSG_ReadChar ();
235 count = MSG_ReadByte ();
236 Mod_FindNonSolidLocation(pos, cl.worldmodel);
237 CL_SparkShower(pos, dir, count);
241 Mod_FindNonSolidLocation(pos, cl.worldmodel);
242 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
245 // LordHavoc: added for improved gore
248 MSG_ReadVector(pos); // mins
249 MSG_ReadVector(pos2); // maxs
250 velspeed = MSG_ReadCoord (); // speed
251 count = MSG_ReadShort (); // number of particles
252 CL_BloodShower(pos, pos2, velspeed, count);
254 case TE_PARTICLECUBE:
255 // general purpose particle effect
256 MSG_ReadVector(pos); // mins
257 MSG_ReadVector(pos2); // maxs
258 MSG_ReadVector(dir); // dir
259 count = MSG_ReadShort (); // number of particles
260 colorStart = MSG_ReadByte (); // color
261 colorLength = MSG_ReadByte (); // gravity (1 or 0)
262 velspeed = MSG_ReadCoord (); // randomvel
263 CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
266 case TE_PARTICLERAIN:
267 // general purpose particle effect
268 MSG_ReadVector(pos); // mins
269 MSG_ReadVector(pos2); // maxs
270 MSG_ReadVector(dir); // dir
271 count = MSG_ReadShort (); // number of particles
272 colorStart = MSG_ReadByte (); // color
273 CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
276 case TE_PARTICLESNOW:
277 // general purpose particle effect
278 MSG_ReadVector(pos); // mins
279 MSG_ReadVector(pos2); // maxs
280 MSG_ReadVector(dir); // dir
281 count = MSG_ReadShort (); // number of particles
282 colorStart = MSG_ReadByte (); // color
283 CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
287 // bullet hitting wall
289 Mod_FindNonSolidLocation(pos, cl.worldmodel);
290 // LordHavoc: changed to dust shower
291 CL_SparkShower(pos, vec3_origin, 15);
295 // quad bullet hitting wall
297 Mod_FindNonSolidLocation(pos, cl.worldmodel);
298 CL_SparkShower(pos, vec3_origin, 15);
299 CL_AllocDlight (NULL, pos, 200, 0.1f, 0.1f, 1.0f, 1000, 0.2);
305 Mod_FindNonSolidLocation(pos, cl.worldmodel);
306 CL_ParticleExplosion (pos, false);
307 // LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
308 CL_AllocDlight (NULL, pos, 350, 1.25f, 1.0f, 0.5f, 700, 0.5);
309 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
312 case TE_EXPLOSIONQUAD:
313 // quad rocket explosion
315 Mod_FindNonSolidLocation(pos, cl.worldmodel);
316 CL_ParticleExplosion (pos, false);
317 CL_AllocDlight (NULL, pos, 600, 0.5f, 0.4f, 1.0f, 1200, 0.5);
318 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
322 // Nehahra movie colored lighting explosion
324 Mod_FindNonSolidLocation(pos, cl.worldmodel);
325 CL_ParticleExplosion (pos, false);
326 CL_AllocDlight (NULL, pos, 350, MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord(), 700, 0.5);
327 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
330 case TE_EXPLOSIONRGB:
331 // colored lighting explosion
333 Mod_FindNonSolidLocation(pos, cl.worldmodel);
334 CL_ParticleExplosion (pos, false);
335 color[0] = MSG_ReadByte() * (1.0 / 255.0);
336 color[1] = MSG_ReadByte() * (1.0 / 255.0);
337 color[2] = MSG_ReadByte() * (1.0 / 255.0);
338 CL_AllocDlight (NULL, pos, 350, color[0], color[1], color[2], 700, 0.5);
339 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
342 case TE_TAREXPLOSION:
345 Mod_FindNonSolidLocation(pos, cl.worldmodel);
346 CL_BlobExplosion (pos);
348 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
349 CL_AllocDlight (NULL, pos, 600, 0.8f, 0.4f, 1.0f, 1200, 0.5);
350 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
355 Mod_FindNonSolidLocation(pos, cl.worldmodel);
356 CL_AllocDlight (NULL, pos, 200, 1, 1, 1, 1000, 0.2);
361 Mod_FindNonSolidLocation(pos, cl.worldmodel);
362 radius = MSG_ReadByte() * 8;
363 velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
364 color[0] = MSG_ReadByte() * (1.0 / 255.0);
365 color[1] = MSG_ReadByte() * (1.0 / 255.0);
366 color[2] = MSG_ReadByte() * (1.0 / 255.0);
367 CL_AllocDlight (NULL, pos, radius, color[0], color[1], color[2], radius / velspeed, velspeed);
373 count = MSG_ReadByte();
374 CL_Flames(pos, dir, count);
380 cl_model_bolt = Mod_ForName("progs/bolt.mdl", true, false, false);
381 CL_ParseBeam (cl_model_bolt);
387 cl_model_bolt2 = Mod_ForName("progs/bolt2.mdl", true, false, false);
388 CL_ParseBeam (cl_model_bolt2);
394 cl_model_bolt3 = Mod_ForName("progs/bolt3.mdl", true, false, false);
395 CL_ParseBeam (cl_model_bolt3);
400 // grappling hook beam
402 cl_model_beam = Mod_ForName("progs/beam.mdl", true, false, false);
403 CL_ParseBeam (cl_model_beam);
407 // LordHavoc: for compatibility with the Nehahra movie...
408 case TE_LIGHTNING4NEH:
409 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true, false, false));
413 pos[0] = MSG_ReadCoord ();
414 pos[1] = MSG_ReadCoord ();
415 pos[2] = MSG_ReadCoord ();
420 pos[0] = MSG_ReadCoord ();
421 pos[1] = MSG_ReadCoord ();
422 pos[2] = MSG_ReadCoord ();
423 CL_AllocDlight (NULL, pos, 1000, 1.25f, 1.25f, 1.25f, 3000, 99.0f);
424 // CL_TeleportSplash (pos);
428 // color mapped explosion
430 Mod_FindNonSolidLocation(pos, cl.worldmodel);
431 colorStart = MSG_ReadByte ();
432 colorLength = MSG_ReadByte ();
433 CL_ParticleExplosion2 (pos, colorStart, colorLength);
434 tempcolor = (qbyte *)&d_8to24table[(rand()%colorLength) + colorStart];
435 CL_AllocDlight (NULL, pos, 350, tempcolor[0] * (1.0f / 255.0f), tempcolor[1] * (1.0f / 255.0f), tempcolor[2] * (1.0f / 255.0f), 700, 0.5);
436 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
440 Host_Error ("CL_ParseTEnt: bad type %d", type);
445 void CL_ClearTempEntities (void)
447 cl_num_temp_entities = 0;
455 entity_t *CL_NewTempEntity (void)
459 if (r_refdef.numentities >= r_refdef.maxentities)
461 if (cl_num_temp_entities >= cl_max_temp_entities)
463 ent = &cl_temp_entities[cl_num_temp_entities++];
464 memset (ent, 0, sizeof(*ent));
465 r_refdef.entities[r_refdef.numentities++] = &ent->render;
467 ent->render.colormap = -1; // no special coloring
468 ent->render.scale = 1;
469 ent->render.alpha = 1;
473 void CL_RelinkBeams (void)
483 for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
485 if (!b->model || b->endtime < cl.time)
488 // if coming from the player, update the start position
489 //if (b->entity == cl.viewentity)
490 // VectorCopy (cl_entities[cl.viewentity].render.origin, b->start);
493 VectorCopy (cl_entities[b->entity].render.origin, b->start);
497 // calculate pitch and yaw
498 VectorSubtract (b->end, b->start, dist);
500 if (dist[1] == 0 && dist[0] == 0)
510 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
514 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
515 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
520 // add new entities for the lightning
521 VectorCopy (b->start, org);
522 d = VectorNormalizeLength(dist);
525 ent = CL_NewTempEntity ();
528 VectorCopy (org, ent->render.origin);
529 ent->render.model = b->model;
530 ent->render.effects = EF_FULLBRIGHT;
531 ent->render.angles[0] = pitch;
532 ent->render.angles[1] = yaw;
533 ent->render.angles[2] = rand()%360;
534 CL_BoundingBoxForEntity(&ent->render);
535 VectorMA(org, 30, dist, org);