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);
107 // attempts to find the nearest non-solid location, used for explosions mainly
108 void FindNonSolidLocation(vec3_t pos)
110 if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
111 pos[0]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
112 pos[0]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
114 pos[1]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
115 pos[1]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
117 pos[2]-=1;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
118 pos[2]+=2;if (SV_HullPointContents (cl.worldmodel->hulls, 0, pos) != CONTENTS_SOLID) return;
127 void CL_ParseTEnt (void)
135 int colorStart, colorLength, count;
139 type = MSG_ReadByte ();
142 case TE_WIZSPIKE: // spike hitting wall
143 pos[0] = MSG_ReadCoord ();
144 pos[1] = MSG_ReadCoord ();
145 pos[2] = MSG_ReadCoord ();
146 R_RunParticleEffect (pos, vec3_origin, 20, 30);
147 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
150 case TE_KNIGHTSPIKE: // spike hitting wall
151 pos[0] = MSG_ReadCoord ();
152 pos[1] = MSG_ReadCoord ();
153 pos[2] = MSG_ReadCoord ();
154 R_RunParticleEffect (pos, vec3_origin, 226, 20);
155 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
158 case TE_SPIKE: // spike hitting wall
159 pos[0] = MSG_ReadCoord ();
160 pos[1] = MSG_ReadCoord ();
161 pos[2] = MSG_ReadCoord ();
162 // LordHavoc: changed to spark shower
163 R_SparkShower(pos, vec3_origin, 15);
164 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
166 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
171 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
173 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
175 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
178 case TE_SPIKEQUAD: // quad spike hitting wall
179 pos[0] = MSG_ReadCoord ();
180 pos[1] = MSG_ReadCoord ();
181 pos[2] = MSG_ReadCoord ();
182 // LordHavoc: changed to spark shower
183 R_SparkShower(pos, vec3_origin, 15);
184 //R_RunParticleEffect (pos, vec3_origin, 0, 10);
185 dl = CL_AllocDlight (0);
186 VectorCopy (pos, dl->origin);
188 dl->die = cl.time + 0.2;
190 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
191 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
193 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
198 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
200 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
202 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
205 case TE_SUPERSPIKE: // super spike hitting wall
206 pos[0] = MSG_ReadCoord ();
207 pos[1] = MSG_ReadCoord ();
208 pos[2] = MSG_ReadCoord ();
209 // LordHavoc: changed to dust shower
210 R_SparkShower(pos, vec3_origin, 30);
211 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
213 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
218 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
220 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
222 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
225 case TE_SUPERSPIKEQUAD: // quad super spike hitting wall
226 pos[0] = MSG_ReadCoord ();
227 pos[1] = MSG_ReadCoord ();
228 pos[2] = MSG_ReadCoord ();
229 // LordHavoc: changed to dust shower
230 R_SparkShower(pos, vec3_origin, 30);
231 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
232 dl = CL_AllocDlight (0);
233 VectorCopy (pos, dl->origin);
235 dl->die = cl.time + 0.2;
237 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
239 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
244 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
246 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
248 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
251 // LordHavoc: added for improved blood splatters
252 case TE_BLOOD: // blood puff
253 pos[0] = MSG_ReadCoord ();
254 pos[1] = MSG_ReadCoord ();
255 pos[2] = MSG_ReadCoord ();
256 dir[0] = MSG_ReadChar ();
257 dir[1] = MSG_ReadChar ();
258 dir[2] = MSG_ReadChar ();
259 count = MSG_ReadByte (); // amount of particles
262 case TE_BLOOD2: // blood puff
263 pos[0] = MSG_ReadCoord ();
264 pos[1] = MSG_ReadCoord ();
265 pos[2] = MSG_ReadCoord ();
268 case TE_SPARK: // spark shower
269 pos[0] = MSG_ReadCoord ();
270 pos[1] = MSG_ReadCoord ();
271 pos[2] = MSG_ReadCoord ();
272 dir[0] = MSG_ReadChar ();
273 dir[1] = MSG_ReadChar ();
274 dir[2] = MSG_ReadChar ();
275 count = MSG_ReadByte (); // amount of particles
276 R_SparkShower(pos, dir, count);
278 // LordHavoc: added for improved gore
279 case TE_BLOODSHOWER: // vaporized body
280 pos[0] = MSG_ReadCoord (); // mins
281 pos[1] = MSG_ReadCoord ();
282 pos[2] = MSG_ReadCoord ();
283 dir[0] = MSG_ReadCoord (); // maxs
284 dir[1] = MSG_ReadCoord ();
285 dir[2] = MSG_ReadCoord ();
286 velspeed = MSG_ReadCoord (); // speed
287 count = MSG_ReadShort (); // number of particles
288 R_BloodShower(pos, dir, velspeed, count);
290 case TE_PARTICLECUBE: // general purpose particle effect
291 pos[0] = MSG_ReadCoord (); // mins
292 pos[1] = MSG_ReadCoord ();
293 pos[2] = MSG_ReadCoord ();
294 pos2[0] = MSG_ReadCoord (); // maxs
295 pos2[1] = MSG_ReadCoord ();
296 pos2[2] = MSG_ReadCoord ();
297 dir[0] = MSG_ReadCoord (); // dir
298 dir[1] = MSG_ReadCoord ();
299 dir[2] = MSG_ReadCoord ();
300 count = MSG_ReadShort (); // number of particles
301 colorStart = MSG_ReadByte (); // color
302 colorLength = MSG_ReadByte (); // gravity (1 or 0)
303 velspeed = MSG_ReadCoord (); // randomvel
304 R_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
307 case TE_PARTICLERAIN: // general purpose particle effect
308 pos[0] = MSG_ReadCoord (); // mins
309 pos[1] = MSG_ReadCoord ();
310 pos[2] = MSG_ReadCoord ();
311 pos2[0] = MSG_ReadCoord (); // maxs
312 pos2[1] = MSG_ReadCoord ();
313 pos2[2] = MSG_ReadCoord ();
314 dir[0] = MSG_ReadCoord (); // dir
315 dir[1] = MSG_ReadCoord ();
316 dir[2] = MSG_ReadCoord ();
317 count = MSG_ReadShort (); // number of particles
318 colorStart = MSG_ReadByte (); // color
319 R_ParticleRain(pos, pos2, dir, count, colorStart, 0);
322 case TE_PARTICLESNOW: // general purpose particle effect
323 pos[0] = MSG_ReadCoord (); // mins
324 pos[1] = MSG_ReadCoord ();
325 pos[2] = MSG_ReadCoord ();
326 pos2[0] = MSG_ReadCoord (); // maxs
327 pos2[1] = MSG_ReadCoord ();
328 pos2[2] = MSG_ReadCoord ();
329 dir[0] = MSG_ReadCoord (); // dir
330 dir[1] = MSG_ReadCoord ();
331 dir[2] = MSG_ReadCoord ();
332 count = MSG_ReadShort (); // number of particles
333 colorStart = MSG_ReadByte (); // color
334 R_ParticleRain(pos, pos2, dir, count, colorStart, 1);
337 case TE_GUNSHOT: // bullet hitting wall
338 pos[0] = MSG_ReadCoord ();
339 pos[1] = MSG_ReadCoord ();
340 pos[2] = MSG_ReadCoord ();
341 // LordHavoc: changed to dust shower
342 R_SparkShower(pos, vec3_origin, 15);
343 //R_RunParticleEffect (pos, vec3_origin, 0, 20);
346 case TE_GUNSHOTQUAD: // quad bullet hitting wall
347 pos[0] = MSG_ReadCoord ();
348 pos[1] = MSG_ReadCoord ();
349 pos[2] = MSG_ReadCoord ();
350 R_SparkShower(pos, vec3_origin, 15);
351 dl = CL_AllocDlight (0);
352 VectorCopy (pos, dl->origin);
354 dl->die = cl.time + 0.2;
356 dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
359 case TE_EXPLOSION: // rocket explosion
360 pos[0] = MSG_ReadCoord ();
361 pos[1] = MSG_ReadCoord ();
362 pos[2] = MSG_ReadCoord ();
363 FindNonSolidLocation(pos);
364 R_ParticleExplosion (pos, false);
365 // R_BlastParticles (pos, 120, 120);
366 dl = CL_AllocDlight (0);
367 VectorCopy (pos, dl->origin);
369 dl->die = cl.time + 0.5;
371 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
372 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
375 case TE_EXPLOSIONQUAD: // quad rocket explosion
376 pos[0] = MSG_ReadCoord ();
377 pos[1] = MSG_ReadCoord ();
378 pos[2] = MSG_ReadCoord ();
379 FindNonSolidLocation(pos);
380 R_ParticleExplosion (pos, false);
381 // R_BlastParticles (pos, 120, 480);
382 dl = CL_AllocDlight (0);
383 VectorCopy (pos, dl->origin);
385 dl->die = cl.time + 0.5;
387 dl->color[0] = 0.5;dl->color[1] = 0.4;dl->color[2] = 1.0;
388 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
392 case TE_SMOKEEXPLOSION: // rocket explosion with a cloud of smoke
393 pos[0] = MSG_ReadCoord ();
394 pos[1] = MSG_ReadCoord ();
395 pos[2] = MSG_ReadCoord ();
396 FindNonSolidLocation(pos);
397 R_ParticleExplosion (pos, true);
398 dl = CL_AllocDlight (0);
399 VectorCopy (pos, dl->origin);
401 dl->die = cl.time + 0.5;
403 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
404 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
408 case TE_EXPLOSION3: // Nehahra movie colored lighting explosion
409 pos[0] = MSG_ReadCoord ();
410 pos[1] = MSG_ReadCoord ();
411 pos[2] = MSG_ReadCoord ();
412 FindNonSolidLocation(pos);
413 R_ParticleExplosion (pos, false);
414 // R_BlastParticles (pos, 120, 120);
415 dl = CL_AllocDlight (0);
416 VectorCopy (pos, dl->origin);
418 dl->die = cl.time + 0.5;
420 dl->color[0] = MSG_ReadCoord();dl->color[1] = MSG_ReadCoord();dl->color[2] = MSG_ReadCoord();
421 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
424 case TE_EXPLOSIONRGB: // colored lighting explosion
425 pos[0] = MSG_ReadCoord ();
426 pos[1] = MSG_ReadCoord ();
427 pos[2] = MSG_ReadCoord ();
428 FindNonSolidLocation(pos);
429 R_ParticleExplosion (pos, false);
430 // R_BlastParticles (pos, 120, 120);
431 dl = CL_AllocDlight (0);
432 VectorCopy (pos, dl->origin);
434 dl->die = cl.time + 0.5;
436 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);
437 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
440 case TE_TAREXPLOSION: // tarbaby explosion
441 pos[0] = MSG_ReadCoord ();
442 pos[1] = MSG_ReadCoord ();
443 pos[2] = MSG_ReadCoord ();
444 FindNonSolidLocation(pos);
445 R_BlobExplosion (pos);
446 // R_BlastParticles (pos, 120, 120);
448 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
449 dl = CL_AllocDlight (0);
450 VectorCopy (pos, dl->origin);
452 dl->die = cl.time + 0.5;
454 dl->color[0] = 0.8;dl->color[1] = 0.4;dl->color[2] = 1.0;
455 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
458 case TE_LIGHTNING1: // lightning bolts
459 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
462 case TE_LIGHTNING2: // lightning bolts
463 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
466 case TE_LIGHTNING3: // lightning bolts
467 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
471 case TE_BEAM: // grappling hook beam
472 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
476 // LordHavoc: for compatibility with the Nehahra movie...
477 case TE_LIGHTNING4NEH:
478 CL_ParseBeam (Mod_ForName(MSG_ReadString(), true));
482 pos[0] = MSG_ReadCoord ();
483 pos[1] = MSG_ReadCoord ();
484 pos[2] = MSG_ReadCoord ();
489 pos[0] = MSG_ReadCoord ();
490 pos[1] = MSG_ReadCoord ();
491 pos[2] = MSG_ReadCoord ();
492 R_TeleportSplash (pos);
495 case TE_EXPLOSION2: // color mapped explosion
496 pos[0] = MSG_ReadCoord ();
497 pos[1] = MSG_ReadCoord ();
498 pos[2] = MSG_ReadCoord ();
499 FindNonSolidLocation(pos);
500 colorStart = MSG_ReadByte ();
501 colorLength = MSG_ReadByte ();
502 R_ParticleExplosion2 (pos, colorStart, colorLength);
503 // R_BlastParticles (pos, 80, 80);
504 dl = CL_AllocDlight (0);
505 VectorCopy (pos, dl->origin);
507 dl->die = cl.time + 0.5;
509 tempcolor = (byte *)&d_8to24table[(rand()%colorLength) + colorStart];
510 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);
511 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
515 Host_Error ("CL_ParseTEnt: bad type %d", type);
525 entity_t *CL_NewTempEntity (void)
529 if (cl_numvisedicts == MAX_VISEDICTS)
531 if (num_temp_entities == MAX_TEMP_ENTITIES)
533 ent = &cl_temp_entities[num_temp_entities];
534 memset (ent, 0, sizeof(*ent));
536 cl_visedicts[cl_numvisedicts] = ent;
539 ent->colormap = -1; // no special coloring
542 ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1;
552 void CL_UpdateTEnts (void)
563 num_temp_entities = 0;
566 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
568 if (!b->model || b->endtime < cl.time)
571 // if coming from the player, update the start position
572 if (b->entity == cl.viewentity)
574 VectorCopy (cl_entities[cl.viewentity].origin, b->start);
577 // calculate pitch and yaw
578 VectorSubtract (b->end, b->start, dist);
580 if (dist[1] == 0 && dist[0] == 0)
590 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
594 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
595 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
600 // add new entities for the lightning
601 VectorCopy (b->start, org);
602 d = VectorNormalizeLength(dist);
605 ent = CL_NewTempEntity ();
608 VectorCopy (org, ent->origin);
609 ent->model = b->model;
610 ent->effects = EF_FULLBRIGHT;
611 ent->angles[0] = pitch;
612 ent->angles[1] = yaw;
613 ent->angles[2] = rand()%360;
615 dl = CL_AllocDlight (0);
616 VectorCopy (ent->origin, dl->origin);
617 dl->radius = 100 + (rand()&31);
618 dl->die = cl.time + 0.001;
619 dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 1;
621 VectorMA(org, 30, dist, org);