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_BlastParticles(vec3_t org, vec_t radius, vec_t power);
103 void R_BloodShower (vec3_t mins, vec3_t maxs, float velspeed, int count);
104 void R_ParticleCube (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int gravity, int randomvel);
105 void R_ParticleRain (vec3_t mins, vec3_t maxs, vec3_t dir, int count, int colorbase, int type);
112 void CL_ParseTEnt (void)
120 int colorStart, colorLength, count;
124 type = MSG_ReadByte ();
127 case TE_WIZSPIKE: // spike hitting wall
128 pos[0] = MSG_ReadCoord ();
129 pos[1] = MSG_ReadCoord ();
130 pos[2] = MSG_ReadCoord ();
131 R_RunParticleEffect (pos, vec3_origin, 20, 30);
132 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
135 case TE_KNIGHTSPIKE: // spike hitting wall
136 pos[0] = MSG_ReadCoord ();
137 pos[1] = MSG_ReadCoord ();
138 pos[2] = MSG_ReadCoord ();
139 R_RunParticleEffect (pos, vec3_origin, 226, 20);
140 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
143 case TE_SPIKE: // spike hitting wall
144 pos[0] = MSG_ReadCoord ();
145 pos[1] = MSG_ReadCoord ();
146 pos[2] = MSG_ReadCoord ();
147 // LordHavoc: changed to spark shower
148 R_SparkShower(pos, vec3_origin, 15, 0);
149 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
151 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
156 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
158 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
160 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
163 case TE_SPIKEQUAD: // quad spike hitting wall
164 pos[0] = MSG_ReadCoord ();
165 pos[1] = MSG_ReadCoord ();
166 pos[2] = MSG_ReadCoord ();
167 // LordHavoc: changed to spark shower
168 R_SparkShower(pos, vec3_origin, 15, 0);
169 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
170 dl = CL_AllocDlight (0);
171 VectorCopy (pos, dl->origin);
173 dl->die = cl.time + 0.2;
175 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
176 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
178 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
183 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
185 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
187 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
190 case TE_SUPERSPIKE: // super spike hitting wall
191 pos[0] = MSG_ReadCoord ();
192 pos[1] = MSG_ReadCoord ();
193 pos[2] = MSG_ReadCoord ();
194 // LordHavoc: changed to dust shower
195 R_SparkShower(pos, vec3_origin, 30, 0);
196 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
198 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
203 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
205 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
207 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
210 case TE_SUPERSPIKEQUAD: // quad super spike hitting wall
211 pos[0] = MSG_ReadCoord ();
212 pos[1] = MSG_ReadCoord ();
213 pos[2] = MSG_ReadCoord ();
214 // LordHavoc: changed to dust shower
215 R_SparkShower(pos, vec3_origin, 30, 0);
216 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
217 dl = CL_AllocDlight (0);
218 VectorCopy (pos, dl->origin);
220 dl->die = cl.time + 0.2;
222 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
224 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
229 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
231 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
233 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
236 // LordHavoc: added for improved blood splatters
237 case TE_BLOOD: // blood puff
238 pos[0] = MSG_ReadCoord ();
239 pos[1] = MSG_ReadCoord ();
240 pos[2] = MSG_ReadCoord ();
241 dir[0] = MSG_ReadChar ();
242 dir[1] = MSG_ReadChar ();
243 dir[2] = MSG_ReadChar ();
244 count = MSG_ReadByte (); // amount of particles
245 R_SparkShower(pos, dir, count, 1);
247 case TE_SPARK: // spark shower
248 pos[0] = MSG_ReadCoord ();
249 pos[1] = MSG_ReadCoord ();
250 pos[2] = MSG_ReadCoord ();
251 dir[0] = MSG_ReadChar ();
252 dir[1] = MSG_ReadChar ();
253 dir[2] = MSG_ReadChar ();
254 count = MSG_ReadByte (); // amount of particles
255 R_SparkShower(pos, dir, count, 0);
257 // LordHavoc: added for improved gore
258 case TE_BLOODSHOWER: // vaporized body
259 pos[0] = MSG_ReadCoord (); // mins
260 pos[1] = MSG_ReadCoord ();
261 pos[2] = MSG_ReadCoord ();
262 dir[0] = MSG_ReadCoord (); // maxs
263 dir[1] = MSG_ReadCoord ();
264 dir[2] = MSG_ReadCoord ();
265 velspeed = MSG_ReadCoord (); // speed
266 count = MSG_ReadShort (); // number of particles
267 R_BloodShower(pos, dir, velspeed, count);
269 case TE_PARTICLECUBE: // general purpose particle effect
270 pos[0] = MSG_ReadCoord (); // mins
271 pos[1] = MSG_ReadCoord ();
272 pos[2] = MSG_ReadCoord ();
273 pos2[0] = MSG_ReadCoord (); // maxs
274 pos2[1] = MSG_ReadCoord ();
275 pos2[2] = MSG_ReadCoord ();
276 dir[0] = MSG_ReadCoord (); // dir
277 dir[1] = MSG_ReadCoord ();
278 dir[2] = MSG_ReadCoord ();
279 count = MSG_ReadShort (); // number of particles
280 colorStart = MSG_ReadByte (); // color
281 colorLength = MSG_ReadByte (); // gravity (1 or 0)
282 velspeed = MSG_ReadCoord (); // randomvel
283 R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
286 case TE_PARTICLERAIN: // general purpose particle effect
287 pos[0] = MSG_ReadCoord (); // mins
288 pos[1] = MSG_ReadCoord ();
289 pos[2] = MSG_ReadCoord ();
290 pos2[0] = MSG_ReadCoord (); // maxs
291 pos2[1] = MSG_ReadCoord ();
292 pos2[2] = MSG_ReadCoord ();
293 dir[0] = MSG_ReadCoord (); // dir
294 dir[1] = MSG_ReadCoord ();
295 dir[2] = MSG_ReadCoord ();
296 count = MSG_ReadShort (); // number of particles
297 colorStart = MSG_ReadByte (); // color
298 R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
301 case TE_PARTICLESNOW: // general purpose particle effect
302 pos[0] = MSG_ReadCoord (); // mins
303 pos[1] = MSG_ReadCoord ();
304 pos[2] = MSG_ReadCoord ();
305 pos2[0] = MSG_ReadCoord (); // maxs
306 pos2[1] = MSG_ReadCoord ();
307 pos2[2] = MSG_ReadCoord ();
308 dir[0] = MSG_ReadCoord (); // dir
309 dir[1] = MSG_ReadCoord ();
310 dir[2] = MSG_ReadCoord ();
311 count = MSG_ReadShort (); // number of particles
312 colorStart = MSG_ReadByte (); // color
313 R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
316 case TE_GUNSHOT: // bullet hitting wall
317 pos[0] = MSG_ReadCoord ();
318 pos[1] = MSG_ReadCoord ();
319 pos[2] = MSG_ReadCoord ();
320 // LordHavoc: changed to dust shower
321 R_SparkShower(pos, vec3_origin, 15, 0);
322 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
325 case TE_GUNSHOTQUAD: // quad bullet hitting wall
326 pos[0] = MSG_ReadCoord ();
327 pos[1] = MSG_ReadCoord ();
328 pos[2] = MSG_ReadCoord ();
329 R_SparkShower(pos, vec3_origin, 15, 0);
330 dl = CL_AllocDlight (0);
331 VectorCopy (pos, dl->origin);
333 dl->die = cl.time + 0.2;
335 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
338 case TE_EXPLOSION: // rocket explosion
339 pos[0] = MSG_ReadCoord ();
340 pos[1] = MSG_ReadCoord ();
341 pos[2] = MSG_ReadCoord ();
342 R_ParticleExplosion (pos, false);
343 R_BlastParticles (pos, 120, 120);
344 dl = CL_AllocDlight (0);
345 VectorCopy (pos, dl->origin);
347 dl->die = cl.time + 0.5;
349 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
350 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
353 case TE_EXPLOSIONQUAD: // quad rocket explosion
354 pos[0] = MSG_ReadCoord ();
355 pos[1] = MSG_ReadCoord ();
356 pos[2] = MSG_ReadCoord ();
357 R_ParticleExplosion (pos, false);
358 R_BlastParticles (pos, 120, 480);
359 dl = CL_AllocDlight (0);
360 VectorCopy (pos, dl->origin);
362 dl->die = cl.time + 0.5;
364 dl->color[0] = 0.5;dl->color[1] = 0.4;dl->color[2] = 1.0;
365 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
369 case TE_SMOKEEXPLOSION: // rocket explosion with a cloud of smoke
370 pos[0] = MSG_ReadCoord ();
371 pos[1] = MSG_ReadCoord ();
372 pos[2] = MSG_ReadCoord ();
373 R_ParticleExplosion (pos, true);
374 dl = CL_AllocDlight (0);
375 VectorCopy (pos, dl->origin);
377 dl->die = cl.time + 0.5;
379 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
380 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
384 case TE_EXPLOSION3: // Nehahra movie colored lighting explosion
385 pos[0] = MSG_ReadCoord ();
386 pos[1] = MSG_ReadCoord ();
387 pos[2] = MSG_ReadCoord ();
388 R_ParticleExplosion (pos, false);
389 R_BlastParticles (pos, 120, 120);
390 dl = CL_AllocDlight (0);
391 VectorCopy (pos, dl->origin);
393 dl->die = cl.time + 0.5;
395 dl->color[0] = MSG_ReadCoord();dl->color[1] = MSG_ReadCoord();dl->color[2] = MSG_ReadCoord();
396 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
399 case TE_EXPLOSIONRGB: // colored lighting explosion
400 pos[0] = MSG_ReadCoord ();
401 pos[1] = MSG_ReadCoord ();
402 pos[2] = MSG_ReadCoord ();
403 R_ParticleExplosion (pos, false);
404 R_BlastParticles (pos, 120, 120);
405 dl = CL_AllocDlight (0);
406 VectorCopy (pos, dl->origin);
408 dl->die = cl.time + 0.5;
410 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);
411 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
414 case TE_TAREXPLOSION: // tarbaby explosion
415 pos[0] = MSG_ReadCoord ();
416 pos[1] = MSG_ReadCoord ();
417 pos[2] = MSG_ReadCoord ();
418 R_BlobExplosion (pos);
419 R_BlastParticles (pos, 120, 120);
421 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
422 dl = CL_AllocDlight (0);
423 VectorCopy (pos, dl->origin);
425 dl->die = cl.time + 0.5;
427 dl->color[0] = 0.8;dl->color[1] = 0.4;dl->color[2] = 1.0;
428 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
431 case TE_LIGHTNING1: // lightning bolts
432 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
435 case TE_LIGHTNING2: // lightning bolts
436 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
439 case TE_LIGHTNING3: // lightning bolts
440 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
444 case TE_BEAM: // grappling hook beam
445 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
449 // LordHavoc: for compatibility with the Nehahra movie...
450 case TE_LIGHTNING4NEH:
451 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
455 pos[0] = MSG_ReadCoord ();
456 pos[1] = MSG_ReadCoord ();
457 pos[2] = MSG_ReadCoord ();
462 pos[0] = MSG_ReadCoord ();
463 pos[1] = MSG_ReadCoord ();
464 pos[2] = MSG_ReadCoord ();
465 R_TeleportSplash (pos);
468 case TE_EXPLOSION2: // color mapped explosion
469 pos[0] = MSG_ReadCoord ();
470 pos[1] = MSG_ReadCoord ();
471 pos[2] = MSG_ReadCoord ();
472 colorStart = MSG_ReadByte ();
473 colorLength = MSG_ReadByte ();
474 R_ParticleExplosion2 (pos, colorStart, colorLength);
475 R_BlastParticles (pos, 80, 80);
476 dl = CL_AllocDlight (0);
477 VectorCopy (pos, dl->origin);
479 dl->die = cl.time + 0.5;
481 tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
482 dl->color[0] = tempcolor[0] * (1.0f / 255.0f);dl->color[1] = tempcolor[1] * (1.0f / 255.0f);dl->color[2] = tempcolor[2] * (1.0f / 255.0f);
483 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
487 Host_Error ("CL_ParseTEnt: bad type %d", type);
497 entity_t *CL_NewTempEntity (void)
501 if (cl_numvisedicts == MAX_VISEDICTS)
503 if (num_temp_entities == MAX_TEMP_ENTITIES)
505 ent = &cl_temp_entities[num_temp_entities];
506 memset (ent, 0, sizeof(*ent));
508 cl_visedicts[cl_numvisedicts] = ent;
511 // ent->colormap = vid.colormap;
515 ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
525 void CL_UpdateTEnts (void)
536 num_temp_entities = 0;
539 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
541 if (!b->model || b->endtime < cl.time)
544 // if coming from the player, update the start position
545 if (b->entity == cl.viewentity)
547 VectorCopy (cl_entities[cl.viewentity].origin, b->start);
550 // calculate pitch and yaw
551 VectorSubtract (b->end, b->start, dist);
553 if (dist[1] == 0 && dist[0] == 0)
563 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
567 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
568 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
573 // add new entities for the lightning
574 VectorCopy (b->start, org);
575 d = VectorNormalizeLength(dist);
578 ent = CL_NewTempEntity ();
581 VectorCopy (org, ent->origin);
582 ent->model = b->model;
583 ent->effects = EF_FULLBRIGHT;
584 ent->angles[0] = pitch;
585 ent->angles[1] = yaw;
586 ent->angles[2] = rand()%360;
588 dl = CL_AllocDlight (0);
589 VectorCopy (ent->origin, dl->origin);
590 dl->radius = 100 + (rand()&31);
591 dl->die = cl.time + 0.001;
592 dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 1;
594 VectorMA(org, 30, dist, org);