1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
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.
8 
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.
12 
13 See the GNU General Public License for more details.
14 
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.
18 
19 */
20 // cl_tent.c -- client side temporary entities
21 
22 #include "client.h"
23 
24 typedef enum
25 {
26 	ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
27 } exptype_t;
28 
29 typedef struct
30 {
31 	exptype_t	type;
32 	entity_t	ent;
33 
34 	int			frames;
35 	float		light;
36 	vec3_t		lightcolor;
37 	float		start;
38 	int			baseframe;
39 } explosion_t;
40 
41 
42 
43 #define	MAX_EXPLOSIONS	32
44 explosion_t	cl_explosions[MAX_EXPLOSIONS];
45 
46 
47 #define	MAX_BEAMS	32
48 typedef struct
49 {
50 	int		entity;
51 	int		dest_entity;
52 	struct model_s	*model;
53 	int		endtime;
54 	vec3_t	offset;
55 	vec3_t	start, end;
56 } beam_t;
57 beam_t		cl_beams[MAX_BEAMS];
58 //PMM - added this for player-linked beams.  Currently only used by the plasma beam
59 beam_t		cl_playerbeams[MAX_BEAMS];
60 
61 
62 #define	MAX_LASERS	32
63 typedef struct
64 {
65 	entity_t	ent;
66 	int			endtime;
67 } laser_t;
68 laser_t		cl_lasers[MAX_LASERS];
69 
70 //ROGUE
71 cl_sustain_t	cl_sustains[MAX_SUSTAINS];
72 //ROGUE
73 
74 //PGM
75 extern void CL_TeleportParticles (vec3_t org);
76 //PGM
77 
78 #ifdef QMAX
79 void CL_BloodHit (vec3_t org, vec3_t dir);
80 void CL_BlasterParticles (vec3_t org, vec3_t dir, int count);
81 void CL_ParticleEffectSparks (vec3_t org, vec3_t dir, vec3_t color, int count);
82 #else
83 void CL_BlasterParticles (vec3_t org, vec3_t dir);
84 #endif
85 void CL_BFGExplosionParticles (vec3_t org);
86 // RAFAEL
87 void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
88 
89 #ifdef QMAX
90 void CL_Explosion_Particle (vec3_t org, float scale, qboolean large, qboolean rocket);
91 //void CL_ExplosionParticles (vec3_t org, float alpha);
92 void CL_ExplosionParticles (vec3_t org);
93 #define EXPLOSION_PARTICLES(x) CL_ExplosionParticles((x));
94 #else
95 void CL_ExplosionParticles (vec3_t org);
96 void CL_Explosion_Particle (vec3_t org, float size, qboolean large, qboolean rocket);
97 #define EXPLOSION_PARTICLES(x) CL_ExplosionParticles((x));
98 #endif
99 
100 struct sfx_s	*cl_sfx_ric1;
101 struct sfx_s	*cl_sfx_ric2;
102 struct sfx_s	*cl_sfx_ric3;
103 struct sfx_s	*cl_sfx_lashit;
104 struct sfx_s	*cl_sfx_spark5;
105 struct sfx_s	*cl_sfx_spark6;
106 struct sfx_s	*cl_sfx_spark7;
107 struct sfx_s	*cl_sfx_railg;
108 struct sfx_s	*cl_sfx_rockexp;
109 struct sfx_s	*cl_sfx_grenexp;
110 struct sfx_s	*cl_sfx_watrexp;
111 // RAFAEL
112 struct sfx_s	*cl_sfx_plasexp;
113 struct sfx_s	*cl_sfx_footsteps[4];
114 
115 struct model_s	*cl_mod_explode;
116 struct model_s	*cl_mod_smoke;
117 struct model_s	*cl_mod_flash;
118 struct model_s	*cl_mod_parasite_segment;
119 struct model_s	*cl_mod_grapple_cable;
120 struct model_s	*cl_mod_parasite_tip;
121 struct model_s	*cl_mod_explo4;
122 struct model_s	*cl_mod_bfg_explo;
123 struct model_s	*cl_mod_powerscreen;
124 // RAFAEL
125 struct model_s	*cl_mod_plasmaexplo;
126 
127 //ROGUE
128 struct sfx_s	*cl_sfx_lightning;
129 struct sfx_s	*cl_sfx_disrexp;
130 struct model_s	*cl_mod_lightning;
131 struct model_s	*cl_mod_heatbeam;
132 struct model_s	*cl_mod_monster_heatbeam;
133 struct model_s	*cl_mod_explo4_big;
134 
135 //ROGUE
136 /*
137 =================
138 CL_RegisterTEntSounds
139 =================
140 */
CL_RegisterTEntSounds(void)141 void CL_RegisterTEntSounds (void)
142 {
143 	int		i;
144 	char	name[MAX_QPATH];
145 
146 	// PMM - version stuff
147 //	Com_Printf ("%s\n", ROGUE_VERSION_STRING);
148 	// PMM
149 	cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
150 	cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
151 	cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
152 	cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
153 	cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
154 	cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
155 	cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
156 	cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
157 	cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
158 	cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
159 	cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
160 	// RAFAEL
161 	// cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
162 	S_RegisterSound ("player/land1.wav");
163 
164 	S_RegisterSound ("player/fall2.wav");
165 	S_RegisterSound ("player/fall1.wav");
166 
167 	for (i=0 ; i<4 ; i++)
168 	{
169 		Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
170 		cl_sfx_footsteps[i] = S_RegisterSound (name);
171 	}
172 
173 //PGM
174 	cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
175 	cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
176 	// version stuff
177 //	sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
178 //	if (name[0] == 'w')
179 //		name[0] = 'W';
180 //PGM
181 }
182 
183 /*
184 =================
185 CL_RegisterTEntModels
186 =================
187 */
CL_RegisterTEntModels(void)188 void CL_RegisterTEntModels (void)
189 {
190 	cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
191 	cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
192 	cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
193 	cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
194 	cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
195 	cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
196 	cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
197 	cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
198 	cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
199 
200 re.RegisterModel ("models/objects/laser/tris.md2");
201 re.RegisterModel ("models/objects/grenade2/tris.md2");
202 re.RegisterModel ("models/weapons/v_machn/tris.md2");
203 re.RegisterModel ("models/weapons/v_handgr/tris.md2");
204 re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
205 re.RegisterModel ("models/objects/gibs/bone/tris.md2");
206 re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
207 re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
208 // RAFAEL
209 // re.RegisterModel ("models/objects/blaser/tris.md2");
210 
211 re.RegisterPic ("w_machinegun");
212 re.RegisterPic ("a_bullets");
213 re.RegisterPic ("i_health");
214 re.RegisterPic ("a_grenades");
215 
216 //ROGUE
217 	cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
218 	cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
219 	cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
220 	cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
221 //ROGUE
222 }
223 
224 /*
225 =================
226 CL_ClearTEnts
227 =================
228 */
CL_ClearTEnts(void)229 void CL_ClearTEnts (void)
230 {
231 	memset (cl_beams, 0, sizeof(cl_beams));
232 	memset (cl_explosions, 0, sizeof(cl_explosions));
233 	memset (cl_lasers, 0, sizeof(cl_lasers));
234 
235 //ROGUE
236 	memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
237 	memset (cl_sustains, 0, sizeof(cl_sustains));
238 //ROGUE
239 }
240 
241 #ifdef QMAX
242 #define EXP_DIST 10
CL_R_Explode_SP(vec3_t origin)243 void CL_R_Explode_SP (vec3_t origin)
244 {
245   CL_Explosion_Particle (origin, 0, true, true);
246 }
247 
CL_G_Explode_SP(vec3_t origin)248 void CL_G_Explode_SP (vec3_t origin)
249 {
250   CL_Explosion_Particle (origin, 0, true, false);
251 }
252 #endif
253 
254 /*
255 =================
256 CL_AllocExplosion
257 =================
258 */
CL_AllocExplosion(void)259 explosion_t *CL_AllocExplosion (void)
260 {
261 	int		i;
262 	int		time;
263 	int		index;
264 
265 	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
266 	{
267 		if (cl_explosions[i].type == ex_free)
268 		{
269 			memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
270 			return &cl_explosions[i];
271 		}
272 	}
273 // find the oldest explosion
274 	time = cl.time;
275 	index = 0;
276 
277 	for (i=0 ; i<MAX_EXPLOSIONS ; i++)
278 		if (cl_explosions[i].start < time)
279 		{
280 			time = cl_explosions[i].start;
281 			index = i;
282 		}
283 	memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
284 	return &cl_explosions[index];
285 }
286 
287 /*
288 =================
289 CL_SmokeAndFlash
290 =================
291 */
CL_SmokeAndFlash(vec3_t origin)292 void CL_SmokeAndFlash(vec3_t origin)
293 {
294 	explosion_t	*ex;
295 
296 	ex = CL_AllocExplosion ();
297 	VectorCopy (origin, ex->ent.origin);
298 	ex->type = ex_misc;
299 	ex->frames = 4;
300 	ex->ent.flags = RF_TRANSLUCENT;
301 	ex->start = cl.frame.servertime - 100;
302 	ex->ent.model = cl_mod_smoke;
303 
304 	ex = CL_AllocExplosion ();
305 	VectorCopy (origin, ex->ent.origin);
306 	ex->type = ex_flash;
307 	ex->ent.flags = RF_FULLBRIGHT;
308 	ex->frames = 2;
309 	ex->start = cl.frame.servertime - 100;
310 	ex->ent.model = cl_mod_flash;
311 }
312 
313 /*
314 =================
315 CL_ParseParticles
316 =================
317 */
CL_ParseParticles(void)318 void CL_ParseParticles (void)
319 {
320 	int		color, count;
321 	vec3_t	pos, dir;
322 
323 	MSG_ReadPos (&net_message, pos);
324 	MSG_ReadDir (&net_message, dir);
325 
326 	color = MSG_ReadByte (&net_message);
327 
328 	count = MSG_ReadByte (&net_message);
329 
330 	CL_ParticleEffect (pos, dir, color, count);
331 }
332 
333 /*
334 =================
335 CL_ParseBeam
336 =================
337 */
CL_ParseBeam(struct model_s * model)338 int CL_ParseBeam (struct model_s *model)
339 {
340 	int		ent;
341 	vec3_t	start, end;
342 	beam_t	*b;
343 	int		i;
344 
345 	ent = MSG_ReadShort (&net_message);
346 
347 	MSG_ReadPos (&net_message, start);
348 	MSG_ReadPos (&net_message, end);
349 
350 // override any beam with the same entity
351 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
352 		if (b->entity == ent)
353 		{
354 			b->entity = ent;
355 			b->model = model;
356 			b->endtime = cl.time + 200;
357 			VectorCopy (start, b->start);
358 			VectorCopy (end, b->end);
359 			VectorClear (b->offset);
360 			return ent;
361 		}
362 
363 // find a free beam
364 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
365 	{
366 		if (!b->model || b->endtime < cl.time)
367 		{
368 			b->entity = ent;
369 			b->model = model;
370 			b->endtime = cl.time + 200;
371 			VectorCopy (start, b->start);
372 			VectorCopy (end, b->end);
373 			VectorClear (b->offset);
374 			return ent;
375 		}
376 	}
377 	Com_Printf ("beam list overflow!\n");
378 	return ent;
379 }
380 
381 /*
382 =================
383 CL_ParseBeam2
384 =================
385 */
CL_ParseBeam2(struct model_s * model)386 int CL_ParseBeam2 (struct model_s *model)
387 {
388 	int		ent;
389 	vec3_t	start, end, offset;
390 	beam_t	*b;
391 	int		i;
392 
393 	ent = MSG_ReadShort (&net_message);
394 
395 	MSG_ReadPos (&net_message, start);
396 	MSG_ReadPos (&net_message, end);
397 	MSG_ReadPos (&net_message, offset);
398 
399 //	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
400 
401 // override any beam with the same entity
402 
403 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
404 		if (b->entity == ent)
405 		{
406 			b->entity = ent;
407 			b->model = model;
408 			b->endtime = cl.time + 200;
409 			VectorCopy (start, b->start);
410 			VectorCopy (end, b->end);
411 			VectorCopy (offset, b->offset);
412 			return ent;
413 		}
414 
415 // find a free beam
416 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
417 	{
418 		if (!b->model || b->endtime < cl.time)
419 		{
420 			b->entity = ent;
421 			b->model = model;
422 			b->endtime = cl.time + 200;
423 			VectorCopy (start, b->start);
424 			VectorCopy (end, b->end);
425 			VectorCopy (offset, b->offset);
426 			return ent;
427 		}
428 	}
429 	Com_Printf ("beam list overflow!\n");
430 	return ent;
431 }
432 
433 // ROGUE
434 /*
435 =================
436 CL_ParsePlayerBeam
437   - adds to the cl_playerbeam array instead of the cl_beams array
438 =================
439 */
CL_ParsePlayerBeam(struct model_s * model)440 int CL_ParsePlayerBeam (struct model_s *model)
441 {
442 	int		ent;
443 	vec3_t	start, end, offset;
444 	beam_t	*b;
445 	int		i;
446 
447 	ent = MSG_ReadShort (&net_message);
448 
449 	MSG_ReadPos (&net_message, start);
450 	MSG_ReadPos (&net_message, end);
451 	// PMM - network optimization
452 	if (model == cl_mod_heatbeam)
453 		VectorSet(offset, 2, 7, -3);
454 	else if (model == cl_mod_monster_heatbeam)
455 	{
456 		model = cl_mod_heatbeam;
457 		VectorSet(offset, 0, 0, 0);
458 	}
459 	else
460 		MSG_ReadPos (&net_message, offset);
461 
462 //	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
463 
464 // override any beam with the same entity
465 // PMM - For player beams, we only want one per player (entity) so..
466 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
467 	{
468 		if (b->entity == ent)
469 		{
470 			b->entity = ent;
471 			b->model = model;
472 			b->endtime = cl.time + 200;
473 			VectorCopy (start, b->start);
474 			VectorCopy (end, b->end);
475 			VectorCopy (offset, b->offset);
476 			return ent;
477 		}
478 	}
479 
480 // find a free beam
481 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
482 	{
483 		if (!b->model || b->endtime < cl.time)
484 		{
485 			b->entity = ent;
486 			b->model = model;
487 			b->endtime = cl.time + 100;		// PMM - this needs to be 100 to prevent multiple heatbeams
488 			VectorCopy (start, b->start);
489 			VectorCopy (end, b->end);
490 			VectorCopy (offset, b->offset);
491 			return ent;
492 		}
493 	}
494 	Com_Printf ("beam list overflow!\n");
495 	return ent;
496 }
497 //rogue
498 
499 /*
500 =================
501 CL_ParseLightning
502 =================
503 */
CL_ParseLightning(struct model_s * model)504 int CL_ParseLightning (struct model_s *model)
505 {
506 	int		srcEnt, destEnt;
507 	vec3_t	start, end;
508 	beam_t	*b;
509 	int		i;
510 
511 	srcEnt = MSG_ReadShort (&net_message);
512 	destEnt = MSG_ReadShort (&net_message);
513 
514 	MSG_ReadPos (&net_message, start);
515 	MSG_ReadPos (&net_message, end);
516 
517 // override any beam with the same source AND destination entities
518 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
519 		if (b->entity == srcEnt && b->dest_entity == destEnt)
520 		{
521 //			Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
522 			b->entity = srcEnt;
523 			b->dest_entity = destEnt;
524 			b->model = model;
525 			b->endtime = cl.time + 200;
526 			VectorCopy (start, b->start);
527 			VectorCopy (end, b->end);
528 			VectorClear (b->offset);
529 			return srcEnt;
530 		}
531 
532 // find a free beam
533 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
534 	{
535 		if (!b->model || b->endtime < cl.time)
536 		{
537 //			Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
538 			b->entity = srcEnt;
539 			b->dest_entity = destEnt;
540 			b->model = model;
541 			b->endtime = cl.time + 200;
542 			VectorCopy (start, b->start);
543 			VectorCopy (end, b->end);
544 			VectorClear (b->offset);
545 			return srcEnt;
546 		}
547 	}
548 	Com_Printf ("beam list overflow!\n");
549 	return srcEnt;
550 }
551 
552 /*
553 =================
554 CL_ParseLaser
555 =================
556 */
CL_ParseLaser(int colors)557 void CL_ParseLaser (int colors)
558 {
559 	vec3_t	start;
560 	vec3_t	end;
561 	laser_t	*l;
562 	int		i;
563 
564 	MSG_ReadPos (&net_message, start);
565 	MSG_ReadPos (&net_message, end);
566 
567 	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
568 	{
569 		if (l->endtime < cl.time)
570 		{
571 			l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
572 			VectorCopy (start, l->ent.origin);
573 			VectorCopy (end, l->ent.oldorigin);
574 			l->ent.alpha = 0.30;
575 			l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
576 			l->ent.model = NULL;
577 			l->ent.frame = 4;
578 			l->endtime = cl.time + 100;
579 			return;
580 		}
581 	}
582 }
583 
584 #ifdef QMAX
CL_GunSmokeEffect(vec3_t org,vec3_t dir)585 void CL_GunSmokeEffect (vec3_t org, vec3_t dir)
586 {
587 	vec3_t		velocity, origin;
588 	int			j;
589 
590 	for (j=0 ; j<3 ; j++)
591 	{
592 		origin[j] = org[j] + dir[j]*10;
593 		velocity[j] = 10*dir[j];
594 	}
595 	velocity[2] = 10;
596 
597 	CL_ParticleSmokeEffect (origin, velocity, 0, 10, 10);
598 
599 }
600 #endif
601 //=============
602 //ROGUE
CL_ParseSteam(void)603 void CL_ParseSteam (void)
604 {
605 	vec3_t	pos, dir;
606 	int		id, i;
607 	int		r;
608 	int		cnt;
609 	int		color;
610 	int		magnitude;
611 	cl_sustain_t	*s, *free_sustain;
612 
613 	id = MSG_ReadShort (&net_message);		// an id of -1 is an instant effect
614 	if (id != -1) // sustains
615 	{
616 //			Com_Printf ("Sustain effect id %d\n", id);
617 		free_sustain = NULL;
618 		for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
619 		{
620 			if (s->id == 0)
621 			{
622 				free_sustain = s;
623 				break;
624 			}
625 		}
626 		if (free_sustain)
627 		{
628 			s->id = id;
629 			s->count = MSG_ReadByte (&net_message);
630 			MSG_ReadPos (&net_message, s->org);
631 			MSG_ReadDir (&net_message, s->dir);
632 			r = MSG_ReadByte (&net_message);
633 			s->color = r & 0xff;
634 			s->magnitude = MSG_ReadShort (&net_message);
635 			s->endtime = cl.time + MSG_ReadLong (&net_message);
636 			s->think = CL_ParticleSteamEffect2;
637 			s->thinkinterval = 100;
638 			s->nextthink = cl.time;
639 		}
640 		else
641 		{
642 //				Com_Printf ("No free sustains!\n");
643 			// FIXME - read the stuff anyway
644 			cnt = MSG_ReadByte (&net_message);
645 			MSG_ReadPos (&net_message, pos);
646 			MSG_ReadDir (&net_message, dir);
647 			r = MSG_ReadByte (&net_message);
648 			magnitude = MSG_ReadShort (&net_message);
649 			magnitude = MSG_ReadLong (&net_message); // really interval
650 		}
651 	}
652 	else // instant
653 	{
654 		cnt = MSG_ReadByte (&net_message);
655 		MSG_ReadPos (&net_message, pos);
656 		MSG_ReadDir (&net_message, dir);
657 		r = MSG_ReadByte (&net_message);
658 		magnitude = MSG_ReadShort (&net_message);
659 		color = r & 0xff;
660 		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
661 //		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
662 	}
663 }
664 
CL_ParseWidow(void)665 void CL_ParseWidow (void)
666 {
667 	vec3_t	pos;
668 	int		id, i;
669 	cl_sustain_t	*s, *free_sustain;
670 
671 	id = MSG_ReadShort (&net_message);
672 
673 	free_sustain = NULL;
674 	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
675 	{
676 		if (s->id == 0)
677 		{
678 			free_sustain = s;
679 			break;
680 		}
681 	}
682 	if (free_sustain)
683 	{
684 		s->id = id;
685 		MSG_ReadPos (&net_message, s->org);
686 		s->endtime = cl.time + 2100;
687 		s->think = CL_Widowbeamout;
688 		s->thinkinterval = 1;
689 		s->nextthink = cl.time;
690 	}
691 	else // no free sustains
692 	{
693 		// FIXME - read the stuff anyway
694 		MSG_ReadPos (&net_message, pos);
695 	}
696 }
697 
CL_ParseNuke(void)698 void CL_ParseNuke (void)
699 {
700 	vec3_t	pos;
701 	int		i;
702 	cl_sustain_t	*s, *free_sustain;
703 
704 	free_sustain = NULL;
705 	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
706 	{
707 		if (s->id == 0)
708 		{
709 			free_sustain = s;
710 			break;
711 		}
712 	}
713 	if (free_sustain)
714 	{
715 		s->id = 21000;
716 		MSG_ReadPos (&net_message, s->org);
717 		s->endtime = cl.time + 1000;
718 		s->think = CL_Nukeblast;
719 		s->thinkinterval = 1;
720 		s->nextthink = cl.time;
721 	}
722 	else // no free sustains
723 	{
724 		// FIXME - read the stuff anyway
725 		MSG_ReadPos (&net_message, pos);
726 	}
727 }
728 
729 //ROGUE
730 //=============
731 
732 
733 /*
734 =================
735 CL_ParseTEnt
736 =================
737 */
738 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
739 
CL_ParseTEnt(void)740 void CL_ParseTEnt (void)
741 {
742 	int		type;
743 	vec3_t	pos, pos2, dir;
744 	explosion_t	*ex;
745 	int		cnt;
746 	int		color;
747 	int		r;
748 	int		ent;
749 	int		magnitude;
750 
751 	type = MSG_ReadByte (&net_message);
752 
753 	switch (type)
754 	{
755 	case TE_BLOOD:			// bullet hitting flesh
756 		MSG_ReadPos (&net_message, pos);
757 		MSG_ReadDir (&net_message, dir);
758 #ifdef QMAX
759 		CL_BloodHit (pos, dir);
760 #else
761 		CL_ParticleEffect (pos, dir, 0xe8, 60);
762 #endif
763 		break;
764 
765 	case TE_GUNSHOT:			// bullet hitting wall
766 	case TE_SPARKS:
767 	case TE_BULLET_SPARKS:
768 		MSG_ReadPos (&net_message, pos);
769 		MSG_ReadDir (&net_message, dir);
770 #ifdef QMAX
771 		if (type != TE_SPARKS)
772 		{
773 			CL_GunSmokeEffect (pos, dir);
774 			re.AddStain(pos, 5, -175, -175, -175);
775 		}
776 
777 		if (type == TE_BULLET_SPARKS)
778 		{
779 		  VectorScale(dir, 1.1, dir);
780 		}
781 #else
782 		if (type == TE_GUNSHOT)
783 			CL_ParticleEffect (pos, dir, 0, 40);
784 		else
785 			CL_ParticleEffect (pos, dir, 0xe0, 6);
786 #endif
787 		if (type != TE_SPARKS)
788 		{
789 #ifndef QMAX
790 			CL_SmokeAndFlash(pos);
791 #endif
792 			// impact sound
793 			cnt = rand()&15;
794 			if (cnt == 1)
795 				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
796 			else if (cnt == 2)
797 				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
798 			else if (cnt == 3)
799 				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
800 		}
801 #ifdef QMAX
802 		//adding sparks
803 		{
804 		  vec3_t color = { 255, 125, 10 };
805 		  CL_ParticleEffectSparks (pos, dir, color, (type == TE_GUNSHOT)? 5 : 10);
806 		}
807 #endif
808 		break;
809 
810 	case TE_SCREEN_SPARKS:
811 	case TE_SHIELD_SPARKS:
812 		MSG_ReadPos (&net_message, pos);
813 		MSG_ReadDir (&net_message, dir);
814 		if (type == TE_SCREEN_SPARKS)
815 			CL_ParticleEffect (pos, dir, 0xd0, 40);
816 		else
817 			CL_ParticleEffect (pos, dir, 0xb0, 40);
818 		//FIXME : replace or remove this sound
819 		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
820 		break;
821 
822 	case TE_SHOTGUN:			// bullet hitting wall
823 		MSG_ReadPos (&net_message, pos);
824 		MSG_ReadDir (&net_message, dir);
825 #ifdef QMAX
826 		CL_GunSmokeEffect (pos, dir);
827 		{
828 			vec3_t color = { 200, 100, 10 };
829 			CL_ParticleEffectSparks (pos, dir, color, 8);
830 		}
831 		re.AddStain(pos, 7, -175, -175, -175);
832 #else
833 		CL_ParticleEffect (pos, dir, 0, 20);
834 		CL_SmokeAndFlash(pos);
835 #endif
836 		break;
837 
838 	case TE_SPLASH:			// bullet hitting water
839 		cnt = MSG_ReadByte (&net_message);
840 		MSG_ReadPos (&net_message, pos);
841 		MSG_ReadDir (&net_message, dir);
842 		r = MSG_ReadByte (&net_message);
843 		if (r > 6)
844 			color = 0x00;
845 		else
846 			color = splash_color[r];
847 		CL_ParticleEffect (pos, dir, color, cnt);
848 
849 		if (r == SPLASH_SPARKS)
850 		{
851 			r = rand() & 3;
852 			if (r == 0)
853 				S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
854 			else if (r == 1)
855 				S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
856 			else
857 				S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
858 		}
859 		break;
860 
861 	case TE_LASER_SPARKS:
862 		cnt = MSG_ReadByte (&net_message);
863 		MSG_ReadPos (&net_message, pos);
864 		MSG_ReadDir (&net_message, dir);
865 		color = MSG_ReadByte (&net_message);
866 		CL_ParticleEffect2 (pos, dir, color, cnt);
867 		break;
868 
869 	// RAFAEL
870 	case TE_BLUEHYPERBLASTER:
871 		MSG_ReadPos (&net_message, pos);
872 		MSG_ReadPos (&net_message, dir);
873 #ifdef QMAX
874 		CL_BlasterParticles (pos, dir, 40);
875 #else
876 		CL_BlasterParticles (pos, dir);
877 #endif
878 		break;
879 
880 	case TE_BLASTER:			// blaster hitting wall
881 		MSG_ReadPos (&net_message, pos);
882 		MSG_ReadDir (&net_message, dir);
883 #ifdef QMAX
884 		CL_BlasterParticles (pos, dir, 40);
885 #else
886 		CL_BlasterParticles (pos, dir);
887 
888 		ex = CL_AllocExplosion ();
889 		VectorCopy (pos, ex->ent.origin);
890 		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
891 	// PMM - fixed to correct for pitch of 0
892 		if (dir[0])
893 			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
894 		else if (dir[1] > 0)
895 			ex->ent.angles[1] = 90;
896 		else if (dir[1] < 0)
897 			ex->ent.angles[1] = 270;
898 		else
899 			ex->ent.angles[1] = 0;
900 
901 		ex->type = ex_misc;
902 		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
903 		ex->start = cl.frame.servertime - 100;
904 		ex->light = 150;
905 		ex->lightcolor[0] = 1;
906 		ex->lightcolor[1] = 1;
907 		ex->ent.model = cl_mod_explode;
908 		ex->frames = 4;
909 #endif
910 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
911 		break;
912 
913 	case TE_RAILTRAIL:			// railgun effect
914 		MSG_ReadPos (&net_message, pos);
915 		MSG_ReadPos (&net_message, pos2);
916 		CL_RailTrail (pos, pos2);
917 		S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
918 		break;
919 
920 	case TE_EXPLOSION2:
921 	case TE_GRENADE_EXPLOSION:
922 	case TE_GRENADE_EXPLOSION_WATER:
923 		MSG_ReadPos (&net_message, pos);
924 #ifdef QMAX
925 		CL_G_Explode_SP(pos);
926 
927 		//		if (type!=TE_GRENADE_EXPLOSION_WATER)
928 		//	CL_Radius_Explode_SP(pos, 1.25);
929 		//		CL_ExplosionParticles (pos,1.25);
930 		CL_ExplosionParticles (pos);
931 #else
932 		ex = CL_AllocExplosion ();
933 		VectorCopy (pos, ex->ent.origin);
934 		ex->type = ex_poly;
935 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
936 		ex->start = cl.frame.servertime - 100;
937 		ex->light = 350;
938 		ex->lightcolor[0] = 1.0;
939 		ex->lightcolor[1] = 0.5;
940 		ex->lightcolor[2] = 0.5;
941 		ex->ent.model = cl_mod_explo4;
942 		ex->frames = 19;
943 		ex->baseframe = 30;
944 		ex->ent.angles[1] = rand() % 360;
945 		EXPLOSION_PARTICLES (pos);
946 #endif
947 		if (type == TE_GRENADE_EXPLOSION_WATER)
948 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
949 		else
950 			S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
951 		break;
952 
953 	// RAFAEL
954 	case TE_PLASMA_EXPLOSION:
955 		MSG_ReadPos (&net_message, pos);
956 #ifdef QMAX
957 		CL_R_Explode_SP(pos);
958 //		CL_ExplosionParticles (pos, 1);
959 //		CL_ExplosionParticles (pos);
960 
961 #else
962 		ex = CL_AllocExplosion ();
963 		VectorCopy (pos, ex->ent.origin);
964 		ex->type = ex_poly;
965 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
966 		ex->start = cl.frame.servertime - 100;
967 		ex->light = 350;
968 		ex->lightcolor[0] = 1.0;
969 		ex->lightcolor[1] = 0.5;
970 		ex->lightcolor[2] = 0.5;
971 		ex->ent.angles[1] = rand() % 360;
972 		ex->ent.model = cl_mod_explo4;
973 		if (frand() < 0.5)
974 			ex->baseframe = 15;
975 		ex->frames = 15;
976 		EXPLOSION_PARTICLES (pos);
977 #endif
978 		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
979 		break;
980 
981 	case TE_EXPLOSION1_BIG:
982 #ifdef QMAX
983 	  // PMM
984 		MSG_ReadPos (&net_message, pos);
985 		//		/*
986 //		if (modType("dday"))
987 //		{
988 //			CL_Explosion_Particle (pos, 250, true, true);
989 //			CL_ExplosionParticles (pos, 5);
990 //			CL_Radius_Explode_SP(pos, 5);
991 //		}
992 //		else
993 //		{
994 			CL_Explosion_Particle (pos, 100, true, true);
995 			//CL_ExplosionParticles (pos, 2);
996 			CL_ExplosionParticles (pos);
997 //			CL_Radius_Explode_SP(pos, 2);
998 //		}
999 		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1000 		break;
1001 #endif
1002 	case TE_EXPLOSION1_NP:						// PMM
1003 #ifdef QMAX
1004 	  MSG_ReadPos (&net_message, pos);
1005 	  CL_Explosion_Particle (pos, 50, true, true);
1006 	  CL_ExplosionParticles (pos);
1007 //	  CL_ExplosionParticles (pos, 0.6666666);
1008 //	  CL_Radius_Explode_SP(pos, 0.6666666);
1009 
1010 	  S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
1011 	  break;
1012 #endif
1013 	case TE_EXPLOSION1:
1014 	case TE_ROCKET_EXPLOSION:
1015 	case TE_ROCKET_EXPLOSION_WATER:
1016 		MSG_ReadPos (&net_message, pos);
1017 #ifdef QMAX
1018 		CL_R_Explode_SP(pos);
1019 		//		CL_ExplosionParticles (pos, 1);
1020 		CL_ExplosionParticles (pos);
1021 #else
1022 		ex = CL_AllocExplosion ();
1023 		VectorCopy (pos, ex->ent.origin);
1024 		ex->type = ex_poly;
1025 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1026 		ex->start = cl.frame.servertime - 100;
1027 		ex->light = 350;
1028 		ex->lightcolor[0] = 1.0;
1029 		ex->lightcolor[1] = 0.5;
1030 		ex->lightcolor[2] = 0.5;
1031 		ex->ent.angles[1] = rand() % 360;
1032 		if (type != TE_EXPLOSION1_BIG)				// PMM
1033 			ex->ent.model = cl_mod_explo4;			// PMM
1034 		else
1035 			ex->ent.model = cl_mod_explo4_big;
1036 		if (frand() < 0.5)
1037 			ex->baseframe = 15;
1038 		ex->frames = 15;
1039 		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))		// PMM
1040 			EXPLOSION_PARTICLES (pos);									// PMM
1041 #endif
1042 		if (type == TE_ROCKET_EXPLOSION_WATER)
1043 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1044 		else
1045 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1046 		break;
1047 
1048 	case TE_BFG_EXPLOSION:
1049 		MSG_ReadPos (&net_message, pos);
1050 		ex = CL_AllocExplosion ();
1051 		VectorCopy (pos, ex->ent.origin);
1052 		ex->type = ex_poly;
1053 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1054 		ex->start = cl.frame.servertime - 100;
1055 		ex->light = 350;
1056 		ex->lightcolor[0] = 0.0;
1057 		ex->lightcolor[1] = 1.0;
1058 		ex->lightcolor[2] = 0.0;
1059 		ex->ent.model = cl_mod_bfg_explo;
1060 		ex->ent.flags |= RF_TRANSLUCENT;
1061 		ex->ent.alpha = 0.30;
1062 		ex->frames = 4;
1063 		break;
1064 
1065 	case TE_BFG_BIGEXPLOSION:
1066 		MSG_ReadPos (&net_message, pos);
1067 		CL_BFGExplosionParticles (pos);
1068 		break;
1069 
1070 	case TE_BFG_LASER:
1071 		CL_ParseLaser (0xd0d1d2d3);
1072 		break;
1073 
1074 	case TE_BUBBLETRAIL:
1075 		MSG_ReadPos (&net_message, pos);
1076 		MSG_ReadPos (&net_message, pos2);
1077 		CL_BubbleTrail (pos, pos2);
1078 		break;
1079 
1080 	case TE_PARASITE_ATTACK:
1081 	case TE_MEDIC_CABLE_ATTACK:
1082 		ent = CL_ParseBeam (cl_mod_parasite_segment);
1083 		break;
1084 
1085 	case TE_BOSSTPORT:			// boss teleporting to station
1086 		MSG_ReadPos (&net_message, pos);
1087 		CL_BigTeleportParticles (pos);
1088 		S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
1089 		break;
1090 
1091 	case TE_GRAPPLE_CABLE:
1092 		ent = CL_ParseBeam2 (cl_mod_grapple_cable);
1093 		break;
1094 
1095 	// RAFAEL
1096 	case TE_WELDING_SPARKS:
1097 		cnt = MSG_ReadByte (&net_message);
1098 		MSG_ReadPos (&net_message, pos);
1099 		MSG_ReadDir (&net_message, dir);
1100 		color = MSG_ReadByte (&net_message);
1101 		CL_ParticleEffect2 (pos, dir, color, cnt);
1102 
1103 		ex = CL_AllocExplosion ();
1104 		VectorCopy (pos, ex->ent.origin);
1105 		ex->type = ex_flash;
1106 		// note to self
1107 		// we need a better no draw flag
1108 		ex->ent.flags = RF_BEAM;
1109 		ex->start = cl.frame.servertime - 0.1;
1110 		ex->light = 100 + (rand()%75);
1111 		ex->lightcolor[0] = 1.0;
1112 		ex->lightcolor[1] = 1.0;
1113 		ex->lightcolor[2] = 0.3;
1114 		ex->ent.model = cl_mod_flash;
1115 		ex->frames = 2;
1116 		break;
1117 
1118 	case TE_GREENBLOOD:
1119 		MSG_ReadPos (&net_message, pos);
1120 		MSG_ReadDir (&net_message, dir);
1121 		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
1122 		break;
1123 
1124 	// RAFAEL
1125 	case TE_TUNNEL_SPARKS:
1126 		cnt = MSG_ReadByte (&net_message);
1127 		MSG_ReadPos (&net_message, pos);
1128 		MSG_ReadDir (&net_message, dir);
1129 		color = MSG_ReadByte (&net_message);
1130 		CL_ParticleEffect3 (pos, dir, color, cnt);
1131 		break;
1132 
1133 //=============
1134 //PGM
1135 		// PMM -following code integrated for flechette (different color)
1136 	case TE_BLASTER2:			// green blaster hitting wall
1137 	case TE_FLECHETTE:			// flechette
1138 		MSG_ReadPos (&net_message, pos);
1139 		MSG_ReadDir (&net_message, dir);
1140 
1141 		// PMM
1142 		if (type == TE_BLASTER2)
1143 			CL_BlasterParticles2 (pos, dir, 0xd0);
1144 		else
1145 			CL_BlasterParticles2 (pos, dir, 0x6f); // 75
1146 
1147 		ex = CL_AllocExplosion ();
1148 		VectorCopy (pos, ex->ent.origin);
1149 		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
1150 	// PMM - fixed to correct for pitch of 0
1151 		if (dir[0])
1152 			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
1153 		else if (dir[1] > 0)
1154 			ex->ent.angles[1] = 90;
1155 		else if (dir[1] < 0)
1156 			ex->ent.angles[1] = 270;
1157 		else
1158 			ex->ent.angles[1] = 0;
1159 
1160 		ex->type = ex_misc;
1161 		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
1162 
1163 		// PMM
1164 		if (type == TE_BLASTER2)
1165 			ex->ent.skinnum = 1;
1166 		else // flechette
1167 			ex->ent.skinnum = 2;
1168 
1169 		ex->start = cl.frame.servertime - 100;
1170 		ex->light = 150;
1171 		// PMM
1172 		if (type == TE_BLASTER2)
1173 			ex->lightcolor[1] = 1;
1174 		else // flechette
1175 		{
1176 			ex->lightcolor[0] = 0.19;
1177 			ex->lightcolor[1] = 0.41;
1178 			ex->lightcolor[2] = 0.75;
1179 		}
1180 		ex->ent.model = cl_mod_explode;
1181 		ex->frames = 4;
1182 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1183 		break;
1184 
1185 
1186 	case TE_LIGHTNING:
1187 #ifdef QMAX
1188 	  ent = CL_ParseLightning (10);
1189 #else
1190 	  ent = CL_ParseLightning (cl_mod_lightning);
1191 #endif
1192 		S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
1193 		break;
1194 
1195 	case TE_DEBUGTRAIL:
1196 		MSG_ReadPos (&net_message, pos);
1197 		MSG_ReadPos (&net_message, pos2);
1198 		CL_DebugTrail (pos, pos2);
1199 		break;
1200 
1201 	case TE_PLAIN_EXPLOSION:
1202 		MSG_ReadPos (&net_message, pos);
1203 
1204 		ex = CL_AllocExplosion ();
1205 		VectorCopy (pos, ex->ent.origin);
1206 		ex->type = ex_poly;
1207 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1208 		ex->start = cl.frame.servertime - 100;
1209 		ex->light = 350;
1210 		ex->lightcolor[0] = 1.0;
1211 		ex->lightcolor[1] = 0.5;
1212 		ex->lightcolor[2] = 0.5;
1213 		ex->ent.angles[1] = rand() % 360;
1214 		ex->ent.model = cl_mod_explo4;
1215 		if (frand() < 0.5)
1216 			ex->baseframe = 15;
1217 		ex->frames = 15;
1218 		if (type == TE_ROCKET_EXPLOSION_WATER)
1219 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1220 		else
1221 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1222 		break;
1223 
1224 	case TE_FLASHLIGHT:
1225 		MSG_ReadPos(&net_message, pos);
1226 		ent = MSG_ReadShort(&net_message);
1227 		CL_Flashlight(ent, pos);
1228 		break;
1229 
1230 	case TE_FORCEWALL:
1231 		MSG_ReadPos(&net_message, pos);
1232 		MSG_ReadPos(&net_message, pos2);
1233 		color = MSG_ReadByte (&net_message);
1234 		CL_ForceWall(pos, pos2, color);
1235 		break;
1236 
1237 	case TE_HEATBEAM:
1238 		ent = CL_ParsePlayerBeam (cl_mod_heatbeam);
1239 		break;
1240 
1241 	case TE_MONSTER_HEATBEAM:
1242 		ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam);
1243 		break;
1244 
1245 	case TE_HEATBEAM_SPARKS:
1246 //		cnt = MSG_ReadByte (&net_message);
1247 		cnt = 50;
1248 		MSG_ReadPos (&net_message, pos);
1249 		MSG_ReadDir (&net_message, dir);
1250 //		r = MSG_ReadByte (&net_message);
1251 //		magnitude = MSG_ReadShort (&net_message);
1252 		r = 8;
1253 		magnitude = 60;
1254 		color = r & 0xff;
1255 		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
1256 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1257 		break;
1258 
1259 	case TE_HEATBEAM_STEAM:
1260 //		cnt = MSG_ReadByte (&net_message);
1261 		cnt = 20;
1262 		MSG_ReadPos (&net_message, pos);
1263 		MSG_ReadDir (&net_message, dir);
1264 //		r = MSG_ReadByte (&net_message);
1265 //		magnitude = MSG_ReadShort (&net_message);
1266 //		color = r & 0xff;
1267 		color = 0xe0;
1268 		magnitude = 60;
1269 		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
1270 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1271 		break;
1272 
1273 	case TE_STEAM:
1274 		CL_ParseSteam();
1275 		break;
1276 
1277 	case TE_BUBBLETRAIL2:
1278 //		cnt = MSG_ReadByte (&net_message);
1279 		cnt = 8;
1280 		MSG_ReadPos (&net_message, pos);
1281 		MSG_ReadPos (&net_message, pos2);
1282 		CL_BubbleTrail2 (pos, pos2, cnt);
1283 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1284 		break;
1285 
1286 	case TE_MOREBLOOD:
1287 		MSG_ReadPos (&net_message, pos);
1288 		MSG_ReadDir (&net_message, dir);
1289 		CL_ParticleEffect (pos, dir, 0xe8, 250);
1290 		break;
1291 
1292 	case TE_CHAINFIST_SMOKE:
1293 		dir[0]=0; dir[1]=0; dir[2]=1;
1294 		MSG_ReadPos(&net_message, pos);
1295 		CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
1296 		break;
1297 
1298 	case TE_ELECTRIC_SPARKS:
1299 		MSG_ReadPos (&net_message, pos);
1300 		MSG_ReadDir (&net_message, dir);
1301 //		CL_ParticleEffect (pos, dir, 109, 40);
1302 		CL_ParticleEffect (pos, dir, 0x75, 40);
1303 		//FIXME : replace or remove this sound
1304 		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1305 		break;
1306 
1307 	case TE_TRACKER_EXPLOSION:
1308 		MSG_ReadPos (&net_message, pos);
1309 		CL_ColorFlash (pos, 0, 150, -1, -1, -1);
1310 		CL_ColorExplosionParticles (pos, 0, 1);
1311 //		CL_Tracker_Explode (pos);
1312 		S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
1313 		break;
1314 
1315 	case TE_TELEPORT_EFFECT:
1316 	case TE_DBALL_GOAL:
1317 		MSG_ReadPos (&net_message, pos);
1318 		CL_TeleportParticles (pos);
1319 		break;
1320 
1321 	case TE_WIDOWBEAMOUT:
1322 		CL_ParseWidow ();
1323 		break;
1324 
1325 	case TE_NUKEBLAST:
1326 		CL_ParseNuke ();
1327 		break;
1328 
1329 	case TE_WIDOWSPLASH:
1330 		MSG_ReadPos (&net_message, pos);
1331 		CL_WidowSplash (pos);
1332 		break;
1333 #if 0
1334 	//NEW CUSTOM TEMP EVENTS
1335 
1336 	case TE_LIGHTNINGFLARE: //-psychospaz
1337 		{
1338 			int num, entity;
1339 
1340 			entity = MSG_ReadShort (&net_message);
1341 			num = MSG_ReadShort (&net_message);
1342 			MSG_ReadPos (&net_message, pos);
1343 
1344 			//double up for opacity endurance
1345 			CL_LightningFlare(pos, entity, 2*num);
1346 			CL_LightningFlare(pos, entity, 2*num+1);
1347 		}
1348 		break;
1349 	case TE_SMOKEPUFF: //hahaha server declared stains biotch - psychospaz
1350 		{
1351 			float size;
1352 
1353 			MSG_ReadPos (&net_message, pos);
1354 			MSG_ReadPos (&net_message, dir);
1355 			size = MSG_ReadFloat(&net_message);
1356 
1357 			CL_ParticleSmokeEffect (pos, dir, size);
1358 		}
1359 		break;
1360 	case TE_STAIN: //hahaha server declared stains biotch - psychospaz
1361 		{
1362 			float intens;
1363 			int i, color[3];
1364 
1365 			MSG_ReadPos (&net_message, pos);
1366 			intens = MSG_ReadFloat(&net_message);
1367 			for (i=0;i<3;i++)
1368 				color[i] = -MSG_ReadByte(&net_message);
1369 
1370 			re.AddStain(pos,	intens,
1371 								color[0],
1372 								color[1],
1373 								color[2]);
1374 		}
1375 		break;
1376 	case TE_FOOTPRINT:
1377 		{
1378 			float size;
1379 			vec3_t color, angle;
1380 
1381 			MSG_ReadPos (&net_message, pos);
1382 			MSG_ReadPos (&net_message, dir);
1383 			MSG_ReadPos (&net_message, color);
1384 			size = MSG_ReadFloat(&net_message);
1385 
1386 			angle[0] = anglemod(dir[0] + 180);
1387 			angle[1] = anglemod(dir[1]);
1388 			angle[2] = anglemod(dir[2]);
1389 
1390 			CL_ParticleFootPrint (pos, angle, size, color);
1391 		}
1392 		break;
1393 	case TE_FLAMEBURST:
1394 		{
1395 			float size;
1396 
1397 			MSG_ReadPos (&net_message, pos);
1398 			size = MSG_ReadFloat(&net_message);
1399 
1400 			CL_FlameBurst (pos, size);
1401 		}
1402 		break;
1403 	case TE_LASERSTUN:
1404 		{
1405 			int i;
1406 			float	size;
1407 			vec3_t	color;
1408 
1409 			MSG_ReadPos (&net_message, pos);
1410 			MSG_ReadPos (&net_message, dir);
1411 			size = MSG_ReadFloat(&net_message);
1412 			for (i=0;i<3;i++)
1413 				color[i] = (float)MSG_ReadByte(&net_message);
1414 
1415 			CL_LaserStun (pos, dir, color, size);
1416 		}
1417 		break;
1418 	case TE_STUNBLAST:
1419 		{
1420 			int i;
1421 			float	size;
1422 			vec3_t	color;
1423 
1424 			MSG_ReadPos (&net_message, pos);
1425 			size = MSG_ReadFloat(&net_message);
1426 			for (i=0;i<3;i++)
1427 				color[i] = (float)MSG_ReadByte(&net_message);
1428 
1429 			CL_StunBlast (pos, color, size);
1430 		}
1431 		break;
1432 	case TE_DISRUPTOR_EXPLOSION:
1433 		{
1434 			float	size;
1435 
1436 			MSG_ReadPos (&net_message, pos);
1437 			size = MSG_ReadFloat(&net_message);
1438 
1439 			CL_Disruptor_Explosion_Particle (pos, size);
1440 
1441 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1442 		}
1443 		break;
1444 	case TE_DISINTEGRATE:
1445 		{
1446 			ent = MSG_ReadByte(&net_message);
1447 			MSG_ReadPos (&net_message, pos);
1448 			CL_Disintegrate (pos, ent);
1449 		}
1450 		break;
1451 	case TE_LENSFLARE:
1452 		{
1453 			float size, time;
1454 
1455 			MSG_ReadPos (&net_message, pos);
1456 			MSG_ReadPos (&net_message, dir);
1457 			size = MSG_ReadFloat (&net_message);
1458 			time = MSG_ReadFloat (&net_message);
1459 
1460 			CL_LensFlare(pos, dir, size, time);
1461 		}
1462 		break;
1463 	case TE_WEATHERFX:
1464 		{
1465 			vec3_t color;
1466 			int   type;
1467 			float size, time;
1468 
1469 			MSG_ReadPos (&net_message, pos);
1470 			MSG_ReadPos (&net_message, dir);
1471 			MSG_ReadPos (&net_message, color);
1472 			type = MSG_ReadByte (&net_message);
1473 			size = MSG_ReadFloat (&net_message);
1474 			time = MSG_ReadFloat (&net_message);
1475 
1476 			CL_WeatherFx(pos, dir, color, type, size, time);
1477 		}
1478 		break;
1479 
1480 #endif
1481 //PGM
1482 //==============
1483 
1484 	default:
1485 		Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
1486 	}
1487 }
1488 
1489 /*
1490 =================
1491 CL_AddBeams
1492 =================
1493 */
CL_AddBeams(void)1494 void CL_AddBeams (void)
1495 {
1496 	int			i,j;
1497 	beam_t		*b;
1498 	vec3_t		dist, org;
1499 	float		d;
1500 	entity_t	ent;
1501 	float		yaw, pitch;
1502 	float		forward;
1503 	float		len, steps;
1504 	float		model_length;
1505 
1506 // update beams
1507 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
1508 	{
1509 		if (!b->model || b->endtime < cl.time)
1510 			continue;
1511 
1512 		// if coming from the player, update the start position
1513 		if (b->entity == cl.playernum+1)	// entity 0 is the world
1514 		{
1515 			VectorCopy (cl.refdef.vieworg, b->start);
1516 			b->start[2] -= 22;	// adjust for view height
1517 		}
1518 		VectorAdd (b->start, b->offset, org);
1519 
1520 	// calculate pitch and yaw
1521 		VectorSubtract (b->end, org, dist);
1522 
1523 		if (dist[1] == 0 && dist[0] == 0)
1524 		{
1525 			yaw = 0;
1526 			if (dist[2] > 0)
1527 				pitch = 90;
1528 			else
1529 				pitch = 270;
1530 		}
1531 		else
1532 		{
1533 	// PMM - fixed to correct for pitch of 0
1534 			if (dist[0])
1535 				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
1536 			else if (dist[1] > 0)
1537 				yaw = 90;
1538 			else
1539 				yaw = 270;
1540 			if (yaw < 0)
1541 				yaw += 360;
1542 
1543 			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
1544 			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
1545 			if (pitch < 0)
1546 				pitch += 360.0;
1547 		}
1548 
1549 	// add new entities for the beams
1550 		d = VectorNormalize(dist);
1551 
1552 		memset (&ent, 0, sizeof(ent));
1553 		if (b->model == cl_mod_lightning)
1554 		{
1555 			model_length = 35.0;
1556 			d-= 20.0;  // correction so it doesn't end in middle of tesla
1557 		}
1558 		else
1559 		{
1560 			model_length = 30.0;
1561 		}
1562 		steps = ceil(d/model_length);
1563 		len = (d-model_length)/(steps-1);
1564 
1565 		// PMM - special case for lightning model .. if the real length is shorter than the model,
1566 		// flip it around & draw it from the end to the start.  This prevents the model from going
1567 		// through the tesla mine (instead it goes through the target)
1568 		if ((b->model == cl_mod_lightning) && (d <= model_length))
1569 		{
1570 //			Com_Printf ("special case\n");
1571 			VectorCopy (b->end, ent.origin);
1572 			// offset to push beam outside of tesla model (negative because dist is from end to start
1573 			// for this beam)
1574 //			for (j=0 ; j<3 ; j++)
1575 //				ent.origin[j] -= dist[j]*10.0;
1576 			ent.model = b->model;
1577 			ent.flags = RF_FULLBRIGHT;
1578 			ent.angles[0] = pitch;
1579 			ent.angles[1] = yaw;
1580 			ent.angles[2] = rand()%360;
1581 			V_AddEntity (&ent);
1582 			return;
1583 		}
1584 		while (d > 0)
1585 		{
1586 			VectorCopy (org, ent.origin);
1587 			ent.model = b->model;
1588 			if (b->model == cl_mod_lightning)
1589 			{
1590 				ent.flags = RF_FULLBRIGHT;
1591 				ent.angles[0] = -pitch;
1592 				ent.angles[1] = yaw + 180.0;
1593 				ent.angles[2] = rand()%360;
1594 			}
1595 			else
1596 			{
1597 				ent.angles[0] = pitch;
1598 				ent.angles[1] = yaw;
1599 				ent.angles[2] = rand()%360;
1600 			}
1601 
1602 //			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
1603 			V_AddEntity (&ent);
1604 
1605 			for (j=0 ; j<3 ; j++)
1606 				org[j] += dist[j]*len;
1607 			d -= model_length;
1608 		}
1609 	}
1610 }
1611 
1612 
1613 /*
1614 //				Com_Printf ("Endpoint:  %f %f %f\n", b->end[0], b->end[1], b->end[2]);
1615 //				Com_Printf ("Pred View Angles:  %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
1616 //				Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
1617 //				VectorCopy (cl.predicted_origin, b->start);
1618 //				b->start[2] += 22;	// adjust for view height
1619 //				if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
1620 //					b->start[2] = cl.refdef.vieworg[2];
1621 //				}
1622 
1623 //				Com_Printf ("Time:  %d %d %f\n", cl.time, cls.realtime, cls.frametime);
1624 */
1625 
1626 extern cvar_t *hand;
1627 
1628 /*
1629 =================
1630 ROGUE - draw player locked beams
1631 CL_AddPlayerBeams
1632 =================
1633 */
CL_AddPlayerBeams(void)1634 void CL_AddPlayerBeams (void)
1635 {
1636 	int			i,j;
1637 	beam_t		*b;
1638 	vec3_t		dist, org;
1639 	float		d;
1640 	entity_t	ent;
1641 	float		yaw, pitch;
1642 	float		forward;
1643 	float		len, steps;
1644 	int		framenum;
1645 	float		model_length;
1646 
1647 	float		hand_multiplier;
1648 	frame_t		*oldframe;
1649 	player_state_t	*ps, *ops;
1650 
1651 	framenum = 0;
1652 
1653 //PMM
1654 	if (hand)
1655 	{
1656 		if (hand->value == 2)
1657 			hand_multiplier = 0;
1658 		else if (hand->value == 1)
1659 			hand_multiplier = -1;
1660 		else
1661 			hand_multiplier = 1;
1662 	}
1663 	else
1664 	{
1665 		hand_multiplier = 1;
1666 	}
1667 //PMM
1668 
1669 // update beams
1670 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
1671 	{
1672 		vec3_t		f,r,u;
1673 		if (!b->model || b->endtime < cl.time)
1674 			continue;
1675 
1676 		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
1677 		{
1678 
1679 			// if coming from the player, update the start position
1680 			if (b->entity == cl.playernum+1)	// entity 0 is the world
1681 			{
1682 				// set up gun position
1683 				// code straight out of CL_AddViewWeapon
1684 				ps = &cl.frame.playerstate;
1685 				j = (cl.frame.serverframe - 1) & UPDATE_MASK;
1686 				oldframe = &cl.frames[j];
1687 				if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
1688 					oldframe = &cl.frame;		// previous frame was dropped or involid
1689 				ops = &oldframe->playerstate;
1690 				for (j=0 ; j<3 ; j++)
1691 				{
1692 					b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
1693 						+ cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
1694 				}
1695 				VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
1696 				VectorMA (     org, b->offset[1], cl.v_forward, org);
1697 				VectorMA (     org, b->offset[2], cl.v_up, org);
1698 				if ((hand) && (hand->value == 2)) {
1699 					VectorMA (org, -1, cl.v_up, org);
1700 				}
1701 				// FIXME - take these out when final
1702 				VectorCopy (cl.v_right, r);
1703 				VectorCopy (cl.v_forward, f);
1704 				VectorCopy (cl.v_up, u);
1705 
1706 			}
1707 			else
1708 				VectorCopy (b->start, org);
1709 		}
1710 		else
1711 		{
1712 			// if coming from the player, update the start position
1713 			if (b->entity == cl.playernum+1)	// entity 0 is the world
1714 			{
1715 				VectorCopy (cl.refdef.vieworg, b->start);
1716 				b->start[2] -= 22;	// adjust for view height
1717 			}
1718 			VectorAdd (b->start, b->offset, org);
1719 		}
1720 
1721 	// calculate pitch and yaw
1722 		VectorSubtract (b->end, org, dist);
1723 
1724 //PMM
1725 		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
1726 		{
1727 			vec_t len;
1728 
1729 			len = VectorLength (dist);
1730 			VectorScale (f, len, dist);
1731 			VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
1732 			VectorMA (dist, b->offset[1], f, dist);
1733 			VectorMA (dist, b->offset[2], u, dist);
1734 			if ((hand) && (hand->value == 2)) {
1735 				VectorMA (org, -1, cl.v_up, org);
1736 			}
1737 		}
1738 //PMM
1739 
1740 		if (dist[1] == 0 && dist[0] == 0)
1741 		{
1742 			yaw = 0;
1743 			if (dist[2] > 0)
1744 				pitch = 90;
1745 			else
1746 				pitch = 270;
1747 		}
1748 		else
1749 		{
1750 	// PMM - fixed to correct for pitch of 0
1751 			if (dist[0])
1752 				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
1753 			else if (dist[1] > 0)
1754 				yaw = 90;
1755 			else
1756 				yaw = 270;
1757 			if (yaw < 0)
1758 				yaw += 360;
1759 
1760 			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
1761 			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
1762 			if (pitch < 0)
1763 				pitch += 360.0;
1764 		}
1765 
1766 		if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
1767 		{
1768 			if (b->entity != cl.playernum+1)
1769 			{
1770 				framenum = 2;
1771 //				Com_Printf ("Third person\n");
1772 				ent.angles[0] = -pitch;
1773 				ent.angles[1] = yaw + 180.0;
1774 				ent.angles[2] = 0;
1775 //				Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
1776 				AngleVectors(ent.angles, f, r, u);
1777 
1778 				// if it's a non-origin offset, it's a player, so use the hardcoded player offset
1779 				if (!VectorCompare (b->offset, vec3_origin))
1780 				{
1781 					VectorMA (org, -(b->offset[0])+1, r, org);
1782 					VectorMA (org, -(b->offset[1]), f, org);
1783 					VectorMA (org, -(b->offset[2])-10, u, org);
1784 				}
1785 				else
1786 				{
1787 					// if it's a monster, do the particle effect
1788 					CL_MonsterPlasma_Shell(b->start);
1789 				}
1790 			}
1791 			else
1792 			{
1793 				framenum = 1;
1794 			}
1795 		}
1796 
1797 		// if it's the heatbeam, draw the particle effect
1798 		if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
1799 		{
1800 			CL_Heatbeam (org, dist);
1801 		}
1802 
1803 	// add new entities for the beams
1804 		d = VectorNormalize(dist);
1805 
1806 		memset (&ent, 0, sizeof(ent));
1807 		if (b->model == cl_mod_heatbeam)
1808 		{
1809 			model_length = 32.0;
1810 		}
1811 		else if (b->model == cl_mod_lightning)
1812 		{
1813 			model_length = 35.0;
1814 			d-= 20.0;  // correction so it doesn't end in middle of tesla
1815 		}
1816 		else
1817 		{
1818 			model_length = 30.0;
1819 		}
1820 		steps = ceil(d/model_length);
1821 		len = (d-model_length)/(steps-1);
1822 
1823 		// PMM - special case for lightning model .. if the real length is shorter than the model,
1824 		// flip it around & draw it from the end to the start.  This prevents the model from going
1825 		// through the tesla mine (instead it goes through the target)
1826 		if ((b->model == cl_mod_lightning) && (d <= model_length))
1827 		{
1828 //			Com_Printf ("special case\n");
1829 			VectorCopy (b->end, ent.origin);
1830 			// offset to push beam outside of tesla model (negative because dist is from end to start
1831 			// for this beam)
1832 //			for (j=0 ; j<3 ; j++)
1833 //				ent.origin[j] -= dist[j]*10.0;
1834 			ent.model = b->model;
1835 			ent.flags = RF_FULLBRIGHT;
1836 			ent.angles[0] = pitch;
1837 			ent.angles[1] = yaw;
1838 			ent.angles[2] = rand()%360;
1839 			V_AddEntity (&ent);
1840 			return;
1841 		}
1842 		while (d > 0)
1843 		{
1844 			VectorCopy (org, ent.origin);
1845 			ent.model = b->model;
1846 			if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
1847 			{
1848 //				ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
1849 //				ent.alpha = 0.3;
1850 				ent.flags = RF_FULLBRIGHT;
1851 				ent.angles[0] = -pitch;
1852 				ent.angles[1] = yaw + 180.0;
1853 				ent.angles[2] = (cl.time) % 360;
1854 //				ent.angles[2] = rand()%360;
1855 				ent.frame = framenum;
1856 			}
1857 			else if (b->model == cl_mod_lightning)
1858 			{
1859 				ent.flags = RF_FULLBRIGHT;
1860 				ent.angles[0] = -pitch;
1861 				ent.angles[1] = yaw + 180.0;
1862 				ent.angles[2] = rand()%360;
1863 			}
1864 			else
1865 			{
1866 				ent.angles[0] = pitch;
1867 				ent.angles[1] = yaw;
1868 				ent.angles[2] = rand()%360;
1869 			}
1870 
1871 //			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
1872 			V_AddEntity (&ent);
1873 
1874 			for (j=0 ; j<3 ; j++)
1875 				org[j] += dist[j]*len;
1876 			d -= model_length;
1877 		}
1878 	}
1879 }
1880 
1881 /*
1882 =================
1883 CL_AddExplosions
1884 =================
1885 */
CL_AddExplosions(void)1886 void CL_AddExplosions (void)
1887 {
1888   entity_t	*ent;
1889   int			i;
1890   explosion_t	*ex;
1891   float		frac;
1892   int			f;
1893 
1894   memset (&ent, 0, sizeof(ent));
1895 
1896   for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
1897     {
1898 		if (ex->type == ex_free)
1899 			continue;
1900 		frac = (cl.time - ex->start)/100.0;
1901 		f = floor(frac);
1902 
1903 		ent = &ex->ent;
1904 
1905 		switch (ex->type)
1906 		{
1907 		case ex_mflash:
1908 			if (f >= ex->frames-1)
1909 				ex->type = ex_free;
1910 			break;
1911 		case ex_misc:
1912 			if (f >= ex->frames-1)
1913 			{
1914 				ex->type = ex_free;
1915 				break;
1916 			}
1917 			ent->alpha = 1.0 - frac/(ex->frames-1);
1918 			break;
1919 		case ex_flash:
1920 			if (f >= 1)
1921 			{
1922 				ex->type = ex_free;
1923 				break;
1924 			}
1925 			ent->alpha = 1.0;
1926 			break;
1927 		case ex_poly:
1928 			if (f >= ex->frames-1)
1929 			{
1930 				ex->type = ex_free;
1931 				break;
1932 			}
1933 
1934 			ent->alpha = (16.0 - (float)f)/16.0;
1935 
1936 			if (f < 10)
1937 			{
1938 				ent->skinnum = (f>>1);
1939 				if (ent->skinnum < 0)
1940 					ent->skinnum = 0;
1941 			}
1942 			else
1943 			{
1944 				ent->flags |= RF_TRANSLUCENT;
1945 				if (f < 13)
1946 					ent->skinnum = 5;
1947 				else
1948 					ent->skinnum = 6;
1949 			}
1950 			break;
1951 		case ex_poly2:
1952 			if (f >= ex->frames-1)
1953 			{
1954 				ex->type = ex_free;
1955 				break;
1956 			}
1957 
1958 			ent->alpha = (5.0 - (float)f)/5.0;
1959 			ent->skinnum = 0;
1960 			ent->flags |= RF_TRANSLUCENT;
1961 			break;
1962 		default:
1963 			break;
1964 		}
1965 
1966 		if (ex->type == ex_free)
1967 			continue;
1968 		if (ex->light)
1969 		{
1970 			V_AddLight (ent->origin, ex->light*ent->alpha,
1971 				ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
1972 		}
1973 
1974 		VectorCopy (ent->origin, ent->oldorigin);
1975 
1976 		if (f < 0)
1977 			f = 0;
1978 		ent->frame = ex->baseframe + f + 1;
1979 		ent->oldframe = ex->baseframe + f;
1980 		ent->backlerp = 1.0 - cl.lerpfrac;
1981 
1982 		V_AddEntity (ent);
1983 	}
1984 }
1985 
1986 
1987 /*
1988 =================
1989 CL_AddLasers
1990 =================
1991 */
CL_AddLasers(void)1992 void CL_AddLasers (void)
1993 {
1994 	laser_t		*l;
1995 	int			i;
1996 
1997 	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
1998 	{
1999 		if (l->endtime >= cl.time)
2000 			V_AddEntity (&l->ent);
2001 	}
2002 }
2003 
2004 /* PMM - CL_Sustains */
CL_ProcessSustain()2005 void CL_ProcessSustain ()
2006 {
2007 	cl_sustain_t	*s;
2008 	int				i;
2009 
2010 	for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
2011 	{
2012 		if (s->id) {
2013 			if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
2014 			{
2015 //				Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
2016 				s->think (s);
2017 			}
2018 			else if (s->endtime < cl.time)
2019 				s->id = 0;
2020 		}
2021 	}
2022 }
2023 
2024 /*
2025 =================
2026 CL_AddTEnts
2027 =================
2028 */
CL_AddTEnts(void)2029 void CL_AddTEnts (void)
2030 {
2031 	CL_AddBeams ();
2032 	// PMM - draw plasma beams
2033 	CL_AddPlayerBeams ();
2034 	CL_AddExplosions ();
2035 	CL_AddLasers ();
2036 	// PMM - set up sustain
2037 	CL_ProcessSustain();
2038 }
2039