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