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 int num_temp_entities;
25 entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
26 beam_t cl_beams[MAX_BEAMS];
29 sfx_t *cl_sfx_knighthit;
41 void CL_InitTEnts (void)
43 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
44 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
45 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
46 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
47 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
48 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
49 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
57 void CL_ParseBeam (model_t *m)
64 ent = MSG_ReadShort ();
66 start[0] = MSG_ReadCoord ();
67 start[1] = MSG_ReadCoord ();
68 start[2] = MSG_ReadCoord ();
70 end[0] = MSG_ReadCoord ();
71 end[1] = MSG_ReadCoord ();
72 end[2] = MSG_ReadCoord ();
74 // override any beam with the same entity
75 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
80 b->endtime = cl.time + 0.2;
81 VectorCopy (start, b->start);
82 VectorCopy (end, b->end);
87 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
89 if (!b->model || b->endtime < cl.time)
93 b->endtime = cl.time + 0.2;
94 VectorCopy (start, b->start);
95 VectorCopy (end, b->end);
99 Con_Printf ("beam list overflow!\n");
102 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
103 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
104 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
111 void CL_ParseTEnt (void)
119 int colorStart, colorLength, count;
123 type = MSG_ReadByte ();
126 case TE_WIZSPIKE: // spike hitting wall
127 pos[0] = MSG_ReadCoord ();
128 pos[1] = MSG_ReadCoord ();
129 pos[2] = MSG_ReadCoord ();
130 R_RunParticleEffect (pos, vec3_origin, 20, 30);
131 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
134 case TE_KNIGHTSPIKE: // spike hitting wall
135 pos[0] = MSG_ReadCoord ();
136 pos[1] = MSG_ReadCoord ();
137 pos[2] = MSG_ReadCoord ();
138 R_RunParticleEffect (pos, vec3_origin, 226, 20);
139 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
142 case TE_SPIKE: // spike hitting wall
143 pos[0] = MSG_ReadCoord ();
144 pos[1] = MSG_ReadCoord ();
145 pos[2] = MSG_ReadCoord ();
146 // LordHavoc: changed to spark shower
147 R_SparkShower(pos, vec3_origin, 15, 0);
148 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
150 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
155 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
157 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
159 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
162 case TE_SPIKEQUAD: // quad spike hitting wall
163 pos[0] = MSG_ReadCoord ();
164 pos[1] = MSG_ReadCoord ();
165 pos[2] = MSG_ReadCoord ();
166 // LordHavoc: changed to spark shower
167 R_SparkShower(pos, vec3_origin, 15, 0);
168 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
169 dl = CL_AllocDlight (0);
170 VectorCopy (pos, dl->origin);
172 dl->die = cl.time + 0.2;
174 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
175 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
177 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
182 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
184 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
186 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
189 case TE_SUPERSPIKE: // super spike hitting wall
190 pos[0] = MSG_ReadCoord ();
191 pos[1] = MSG_ReadCoord ();
192 pos[2] = MSG_ReadCoord ();
193 // LordHavoc: changed to dust shower
194 R_SparkShower(pos, vec3_origin, 30, 0);
195 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
197 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
202 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
204 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
206 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
209 case TE_SUPERSPIKEQUAD: // quad super spike hitting wall
210 pos[0] = MSG_ReadCoord ();
211 pos[1] = MSG_ReadCoord ();
212 pos[2] = MSG_ReadCoord ();
213 // LordHavoc: changed to dust shower
214 R_SparkShower(pos, vec3_origin, 30, 0);
215 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
216 dl = CL_AllocDlight (0);
217 VectorCopy (pos, dl->origin);
219 dl->die = cl.time + 0.2;
221 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
223 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
228 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
230 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
232 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
235 // LordHavoc: added for improved blood splatters
236 case TE_BLOOD: // blood puff
237 pos[0] = MSG_ReadCoord ();
238 pos[1] = MSG_ReadCoord ();
239 pos[2] = MSG_ReadCoord ();
240 dir[0] = MSG_ReadChar ();
241 dir[1] = MSG_ReadChar ();
242 dir[2] = MSG_ReadChar ();
243 count = MSG_ReadByte (); // amount of particles
244 R_SparkShower(pos, dir, count, 1);
246 case TE_SPARK: // spark shower
247 pos[0] = MSG_ReadCoord ();
248 pos[1] = MSG_ReadCoord ();
249 pos[2] = MSG_ReadCoord ();
250 dir[0] = MSG_ReadChar ();
251 dir[1] = MSG_ReadChar ();
252 dir[2] = MSG_ReadChar ();
253 count = MSG_ReadByte (); // amount of particles
254 R_SparkShower(pos, dir, count, 0);
256 // LordHavoc: added for improved gore
257 case TE_BLOODSHOWER: // vaporized body
258 pos[0] = MSG_ReadCoord (); // mins
259 pos[1] = MSG_ReadCoord ();
260 pos[2] = MSG_ReadCoord ();
261 dir[0] = MSG_ReadCoord (); // maxs
262 dir[1] = MSG_ReadCoord ();
263 dir[2] = MSG_ReadCoord ();
264 velspeed = MSG_ReadCoord (); // speed
265 count = MSG_ReadShort (); // number of particles
266 R_BloodShower(pos, dir, velspeed, count);
268 case TE_PARTICLECUBE: // general purpose particle effect
269 pos[0] = MSG_ReadCoord (); // mins
270 pos[1] = MSG_ReadCoord ();
271 pos[2] = MSG_ReadCoord ();
272 pos2[0] = MSG_ReadCoord (); // maxs
273 pos2[1] = MSG_ReadCoord ();
274 pos2[2] = MSG_ReadCoord ();
275 dir[0] = MSG_ReadCoord (); // dir
276 dir[1] = MSG_ReadCoord ();
277 dir[2] = MSG_ReadCoord ();
278 count = MSG_ReadShort (); // number of particles
279 colorStart = MSG_ReadByte (); // color
280 colorLength = MSG_ReadByte (); // gravity (1 or 0)
281 velspeed = MSG_ReadCoord (); // randomvel
282 R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
285 case TE_PARTICLERAIN: // general purpose particle effect
286 pos[0] = MSG_ReadCoord (); // mins
287 pos[1] = MSG_ReadCoord ();
288 pos[2] = MSG_ReadCoord ();
289 pos2[0] = MSG_ReadCoord (); // maxs
290 pos2[1] = MSG_ReadCoord ();
291 pos2[2] = MSG_ReadCoord ();
292 dir[0] = MSG_ReadCoord (); // dir
293 dir[1] = MSG_ReadCoord ();
294 dir[2] = MSG_ReadCoord ();
295 count = MSG_ReadShort (); // number of particles
296 colorStart = MSG_ReadByte (); // color
297 R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
300 case TE_PARTICLESNOW: // general purpose particle effect
301 pos[0] = MSG_ReadCoord (); // mins
302 pos[1] = MSG_ReadCoord ();
303 pos[2] = MSG_ReadCoord ();
304 pos2[0] = MSG_ReadCoord (); // maxs
305 pos2[1] = MSG_ReadCoord ();
306 pos2[2] = MSG_ReadCoord ();
307 dir[0] = MSG_ReadCoord (); // dir
308 dir[1] = MSG_ReadCoord ();
309 dir[2] = MSG_ReadCoord ();
310 count = MSG_ReadShort (); // number of particles
311 colorStart = MSG_ReadByte (); // color
312 R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
315 case TE_GUNSHOT: // bullet hitting wall
316 pos[0] = MSG_ReadCoord ();
317 pos[1] = MSG_ReadCoord ();
318 pos[2] = MSG_ReadCoord ();
319 // LordHavoc: changed to dust shower
320 R_SparkShower(pos, vec3_origin, 15, 0);
321 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
324 case TE_GUNSHOTQUAD: // quad bullet hitting wall
325 pos[0] = MSG_ReadCoord ();
326 pos[1] = MSG_ReadCoord ();
327 pos[2] = MSG_ReadCoord ();
328 R_SparkShower(pos, vec3_origin, 15, 0);
329 dl = CL_AllocDlight (0);
330 VectorCopy (pos, dl->origin);
332 dl->die = cl.time + 0.2;
334 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
337 case TE_EXPLOSION: // rocket explosion
338 pos[0] = MSG_ReadCoord ();
339 pos[1] = MSG_ReadCoord ();
340 pos[2] = MSG_ReadCoord ();
341 R_ParticleExplosion (pos, false);
342 dl = CL_AllocDlight (0);
343 VectorCopy (pos, dl->origin);
345 dl->die = cl.time + 0.5;
347 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
348 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
351 case TE_EXPLOSIONQUAD: // quad rocket explosion
352 pos[0] = MSG_ReadCoord ();
353 pos[1] = MSG_ReadCoord ();
354 pos[2] = MSG_ReadCoord ();
355 R_ParticleExplosion (pos, false);
356 dl = CL_AllocDlight (0);
357 VectorCopy (pos, dl->origin);
359 dl->die = cl.time + 0.5;
361 dl->color[0] = 0.5;dl->color[1] = 0.4;dl->color[2] = 1.0;
362 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
366 case TE_SMOKEEXPLOSION: // rocket explosion with a cloud of smoke
367 pos[0] = MSG_ReadCoord ();
368 pos[1] = MSG_ReadCoord ();
369 pos[2] = MSG_ReadCoord ();
370 R_ParticleExplosion (pos, true);
371 dl = CL_AllocDlight (0);
372 VectorCopy (pos, dl->origin);
374 dl->die = cl.time + 0.5;
376 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
377 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
381 case TE_EXPLOSION3: // Nehahra movie colored lighting explosion
382 pos[0] = MSG_ReadCoord ();
383 pos[1] = MSG_ReadCoord ();
384 pos[2] = MSG_ReadCoord ();
385 R_ParticleExplosion (pos, false);
386 dl = CL_AllocDlight (0);
387 VectorCopy (pos, dl->origin);
389 dl->die = cl.time + 0.5;
391 dl->color[0] = MSG_ReadCoord();dl->color[1] = MSG_ReadCoord();dl->color[2] = MSG_ReadCoord();
392 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
395 case TE_EXPLOSIONRGB: // colored lighting explosion
396 pos[0] = MSG_ReadCoord ();
397 pos[1] = MSG_ReadCoord ();
398 pos[2] = MSG_ReadCoord ();
399 R_ParticleExplosion (pos, false);
400 dl = CL_AllocDlight (0);
401 VectorCopy (pos, dl->origin);
403 dl->die = cl.time + 0.5;
405 dl->color[0] = MSG_ReadByte() * (1.0 / 255.0);dl->color[1] = MSG_ReadByte() * (1.0 / 255.0);dl->color[2] = MSG_ReadByte() * (1.0 / 255.0);
406 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
409 case TE_TAREXPLOSION: // tarbaby explosion
410 pos[0] = MSG_ReadCoord ();
411 pos[1] = MSG_ReadCoord ();
412 pos[2] = MSG_ReadCoord ();
413 R_BlobExplosion (pos);
415 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
418 case TE_LIGHTNING1: // lightning bolts
419 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
422 case TE_LIGHTNING2: // lightning bolts
423 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
426 case TE_LIGHTNING3: // lightning bolts
427 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
431 case TE_BEAM: // grappling hook beam
432 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
436 // LordHavoc: ONLY for compatibility with the Nehahra movie... hack hack hack
437 case TE_LIGHTNING4NEH:
438 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
442 pos[0] = MSG_ReadCoord ();
443 pos[1] = MSG_ReadCoord ();
444 pos[2] = MSG_ReadCoord ();
449 pos[0] = MSG_ReadCoord ();
450 pos[1] = MSG_ReadCoord ();
451 pos[2] = MSG_ReadCoord ();
452 R_TeleportSplash (pos);
455 case TE_EXPLOSION2: // color mapped explosion
456 pos[0] = MSG_ReadCoord ();
457 pos[1] = MSG_ReadCoord ();
458 pos[2] = MSG_ReadCoord ();
459 colorStart = MSG_ReadByte ();
460 colorLength = MSG_ReadByte ();
461 R_ParticleExplosion2 (pos, colorStart, colorLength);
462 dl = CL_AllocDlight (0);
463 VectorCopy (pos, dl->origin);
465 dl->die = cl.time + 0.5;
467 tempcolor = (byte *)&d_8to24table[colorStart+(colorLength >> 1)];
468 dl->color[0] = tempcolor[0];dl->color[1] = tempcolor[1];dl->color[2] = tempcolor[2];
469 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
473 Host_Error ("CL_ParseTEnt: bad type %d", type);
483 entity_t *CL_NewTempEntity (void)
487 if (cl_numvisedicts == MAX_VISEDICTS)
489 if (num_temp_entities == MAX_TEMP_ENTITIES)
491 ent = &cl_temp_entities[num_temp_entities];
492 memset (ent, 0, sizeof(*ent));
494 cl_visedicts[cl_numvisedicts] = ent;
497 ent->colormap = vid.colormap;
500 ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
510 void CL_UpdateTEnts (void)
521 num_temp_entities = 0;
524 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
526 if (!b->model || b->endtime < cl.time)
529 // if coming from the player, update the start position
530 if (b->entity == cl.viewentity)
532 VectorCopy (cl_entities[cl.viewentity].origin, b->start);
535 // calculate pitch and yaw
536 VectorSubtract (b->end, b->start, dist);
538 if (dist[1] == 0 && dist[0] == 0)
548 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
552 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
553 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
558 // add new entities for the lightning
559 VectorCopy (b->start, org);
560 d = VectorNormalizeLength(dist);
563 ent = CL_NewTempEntity ();
566 VectorCopy (org, ent->origin);
567 ent->model = b->model;
568 ent->effects = EF_FULLBRIGHT;
569 ent->angles[0] = pitch;
570 ent->angles[1] = yaw;
571 ent->angles[2] = rand()%360;
573 dl = CL_AllocDlight (0);
574 VectorCopy (ent->origin, dl->origin);
575 dl->radius = 100 + (rand()&31);
576 dl->die = cl.time + 0.001;
577 dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 1;
579 VectorMA(org, 30, dist, org);