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 explosion_s
30 {
31 	struct explosion_s *prev, *next;
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	32
43 explosion_t	cl_explosions[MAX_EXPLOSIONS];
44 explosion_t	cl_explosions_headnode, *cl_free_expl;
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 
75 #if defined(PARTICLESYSTEM)
76 void CL_ExplosionParticles (vec3_t org, float scale, int water);
77 #else
78 void CL_BlasterParticles (vec3_t org, vec3_t dir);
79 void CL_ExplosionParticles (vec3_t org);
80 #endif
81 void CL_BFGExplosionParticles (vec3_t org);
82 // RAFAEL
83 void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
84 
85 struct sfx_s	*cl_sfx_ric1;
86 struct sfx_s	*cl_sfx_ric2;
87 struct sfx_s	*cl_sfx_ric3;
88 struct sfx_s	*cl_sfx_lashit;
89 struct sfx_s	*cl_sfx_spark5;
90 struct sfx_s	*cl_sfx_spark6;
91 struct sfx_s	*cl_sfx_spark7;
92 struct sfx_s	*cl_sfx_railg;
93 struct sfx_s	*cl_sfx_rockexp;
94 struct sfx_s	*cl_sfx_grenexp;
95 struct sfx_s	*cl_sfx_watrexp;
96 // RAFAEL
97 struct sfx_s	*cl_sfx_plasexp;
98 struct sfx_s	*cl_sfx_footsteps[4];
99 /* Knightmare- Lazarus footstep sounds */
100 struct sfx_s	*cl_sfx_metal_footsteps[4];
101 struct sfx_s	*cl_sfx_dirt_footsteps[4];
102 struct sfx_s	*cl_sfx_vent_footsteps[4];
103 struct sfx_s	*cl_sfx_grate_footsteps[4];
104 struct sfx_s	*cl_sfx_tile_footsteps[4];
105 struct sfx_s	*cl_sfx_grass_footsteps[4];
106 struct sfx_s	*cl_sfx_snow_footsteps[4];
107 struct sfx_s	*cl_sfx_carpet_footsteps[4];
108 struct sfx_s	*cl_sfx_force_footsteps[4];
109 struct sfx_s	*cl_sfx_gravel_footsteps[4];
110 struct sfx_s	*cl_sfx_ice_footsteps[4];
111 struct sfx_s	*cl_sfx_sand_footsteps[4];
112 struct sfx_s	*cl_sfx_wood_footsteps[4];
113 struct sfx_s	*cl_sfx_slosh[4];
114 struct sfx_s	*cl_sfx_wade[4];
115 struct sfx_s	*cl_sfx_ladder[4];
116 /* end Knightmare */
117 
118 struct model_s	*cl_mod_explode;
119 struct model_s	*cl_mod_smoke;
120 struct model_s	*cl_mod_flash;
121 struct model_s	*cl_mod_parasite_segment;
122 struct model_s	*cl_mod_grapple_cable;
123 struct model_s	*cl_mod_parasite_tip;
124 struct model_s	*cl_mod_explo4;
125 struct model_s	*cl_mod_bfg_explo;
126 struct model_s	*cl_mod_powerscreen;
127 // RAFAEL
128 struct model_s	*cl_mod_plasmaexplo;
129 
130 //ROGUE
131 struct sfx_s	*cl_sfx_lightning;
132 struct sfx_s	*cl_sfx_disrexp;
133 struct model_s	*cl_mod_lightning;
134 struct model_s	*cl_mod_heatbeam;
135 struct model_s	*cl_mod_monster_heatbeam;
136 struct model_s	*cl_mod_explo4_big;
137 
138 //ROGUE
139 /*
140 =================
141 CL_RegisterTEntSounds
142 =================
143 */
CL_RegisterTEntSounds(void)144 void CL_RegisterTEntSounds (void)
145 {
146 	int		i;
147 	char	name[MAX_QPATH];
148 
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 
161 	S_RegisterSound ("player/land1.wav");
162 	S_RegisterSound ("player/fall2.wav");
163 	S_RegisterSound ("player/fall1.wav");
164 
165 	for (i=0 ; i<4 ; i++) {
166 		Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
167 		cl_sfx_footsteps[i] = S_RegisterSound (name);
168 	}
169 
170 	/* Knightmare- Lazarus footstep sounds */
171 	for (i=0 ; i<4 ; i++) {
172 		Com_sprintf (name, sizeof(name), "player/pl_metal%i.wav", i+1);
173 		cl_sfx_metal_footsteps[i] = S_RegisterSound (name);
174 	}
175 	for (i=0 ; i<4 ; i++) {
176 		Com_sprintf (name, sizeof(name), "player/pl_dirt%i.wav", i+1);
177 		cl_sfx_dirt_footsteps[i] = S_RegisterSound (name);
178 	}
179 	for (i=0 ; i<4 ; i++) {
180 		Com_sprintf (name, sizeof(name), "player/pl_duct%i.wav", i+1);
181 		cl_sfx_vent_footsteps[i] = S_RegisterSound (name);
182 	}
183 	for (i=0 ; i<4 ; i++) {
184 		Com_sprintf (name, sizeof(name), "player/pl_grate%i.wav", i+1);
185 		cl_sfx_grate_footsteps[i] = S_RegisterSound (name);
186 	}
187 	for (i=0 ; i<4 ; i++) {
188 		Com_sprintf (name, sizeof(name), "player/pl_tile%i.wav", i+1);
189 		cl_sfx_tile_footsteps[i] = S_RegisterSound (name);
190 	}
191 	for (i=0 ; i<4 ; i++) {
192 		Com_sprintf (name, sizeof(name), "player/pl_grass%i.wav", i+1);
193 		cl_sfx_grass_footsteps[i] = S_RegisterSound (name);
194 	}
195 	for (i=0 ; i<4 ; i++) {
196 		Com_sprintf (name, sizeof(name), "player/pl_snow%i.wav", i+1);
197 		cl_sfx_snow_footsteps[i] = S_RegisterSound (name);
198 	}
199 	for (i=0 ; i<4 ; i++) {
200 		Com_sprintf (name, sizeof(name), "player/pl_carpet%i.wav", i+1);
201 		cl_sfx_carpet_footsteps[i] = S_RegisterSound (name);
202 	}
203 	for (i=0 ; i<4 ; i++) {
204 		Com_sprintf (name, sizeof(name), "player/pl_force%i.wav", i+1);
205 		cl_sfx_force_footsteps[i] = S_RegisterSound (name);
206 	}
207 	for (i=0 ; i<4 ; i++) {
208 		Com_sprintf (name, sizeof(name), "player/pl_gravel%i.wav", i+1);
209 		cl_sfx_gravel_footsteps[i] = S_RegisterSound (name);
210 	}
211 	for (i=0; i<4; i++) {
212 		Com_sprintf (name, sizeof(name), "player/pl_ice%i.wav", i+1);
213 		cl_sfx_ice_footsteps[i] = S_RegisterSound (name);
214 	}
215 	for (i=0; i<4; i++) {
216 		Com_sprintf (name, sizeof(name), "player/pl_sand%i.wav", i+1);
217 		cl_sfx_sand_footsteps[i] = S_RegisterSound (name);
218 	}
219 	for (i=0; i<4; i++) {
220 		Com_sprintf (name, sizeof(name), "player/pl_wood%i.wav", i+1);
221 		cl_sfx_wood_footsteps[i] = S_RegisterSound (name);
222 	}
223 	for (i=0; i<4; i++) {
224 		Com_sprintf (name, sizeof(name), "player/pl_slosh%i.wav", i+1);
225 		cl_sfx_slosh[i] = S_RegisterSound (name);
226 	}
227 	for (i=0; i<4; i++) {
228 		Com_sprintf (name, sizeof(name), "player/pl_wade%i.wav", i+1);
229 		cl_sfx_wade[i] = S_RegisterSound (name);
230 	}
231 	for (i=0; i<4; i++) {
232 		Com_sprintf (name, sizeof(name), "player/pl_ladder%i.wav", i+1);
233 		cl_sfx_ladder[i] = S_RegisterSound (name);
234 	}
235 	if (cl_footsteps_override->value)
236 		ReadTextureSurfaceAssignments();
237 	/* end Knightmare */
238 
239 
240 //PGM
241 	cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
242 	cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
243 //PGM
244 }
245 
246 /*
247 =================
248 CL_RegisterTEntModels
249 =================
250 */
CL_RegisterTEntModels(void)251 void CL_RegisterTEntModels (void)
252 {
253 	cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
254 	cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
255 	cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
256 	cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
257 	cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
258 	cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
259 	cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
260 	cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
261 	cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
262 
263 	re.RegisterModel ("models/objects/laser/tris.md2");
264 	re.RegisterModel ("models/objects/grenade2/tris.md2");
265 	re.RegisterModel ("models/weapons/v_machn/tris.md2");
266 	re.RegisterModel ("models/weapons/v_handgr/tris.md2");
267 	re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
268 	re.RegisterModel ("models/objects/gibs/bone/tris.md2");
269 	re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
270 	re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
271 
272 	re.RegisterPic ("w_machinegun");
273 	re.RegisterPic ("a_bullets");
274 	re.RegisterPic ("i_health");
275 	re.RegisterPic ("a_grenades");
276 
277 //ROGUE
278 	cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
279 	cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
280 	cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
281 	cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
282 //ROGUE
283 }
284 
285 /*
286 =================
287 CL_ClearTEnts
288 =================
289 */
CL_ClearTEnts(void)290 void CL_ClearTEnts (void)
291 {
292 	int i;
293 	memset (cl_beams, 0, sizeof(cl_beams));
294 	memset (cl_explosions, 0, sizeof(cl_explosions));
295 	memset (cl_lasers, 0, sizeof(cl_lasers));
296 
297 	// link explosions
298 	cl_free_expl = cl_explosions;
299 	cl_explosions_headnode.prev = &cl_explosions_headnode;
300 	cl_explosions_headnode.next = &cl_explosions_headnode;
301 	for ( i = 0; i < MAX_EXPLOSIONS - 1; i++ ) {
302 		cl_explosions[i].next = &cl_explosions[i+1];
303 	}
304 
305 //ROGUE
306 	memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
307 	memset (cl_sustains, 0, sizeof(cl_sustains));
308 //ROGUE
309 }
310 
311 /*
312 =================
313 CL_AllocExplosion
314 =================
315 */
CL_AllocExplosion(void)316 explosion_t *CL_AllocExplosion (void)
317 {
318 	explosion_t *ex;
319 
320 	if ( cl_free_expl )
321 	{ // take a free explosion if possible
322 		ex = cl_free_expl;
323 		cl_free_expl = ex->next;
324 	}
325 	else
326 	{ // grab the oldest one otherwise
327 		ex = cl_explosions_headnode.prev;
328 		ex->prev->next = ex->next;
329 		ex->next->prev = ex->prev;
330 	}
331 
332 	memset ( ex, 0, sizeof (*ex) );
333 	ex->start = cl.frame.servertime - 100;
334 
335 	// put the decal at the start of the list
336 	ex->prev = &cl_explosions_headnode;
337 	ex->next = cl_explosions_headnode.next;
338 	ex->next->prev = ex;
339 	ex->prev->next = ex;
340 
341 	return ex;
342 }
343 
344 /*
345 =================
346 CL_FreeExplosion
347 =================
348 */
CL_FreeExplosion(explosion_t * ex)349 void CL_FreeExplosion ( explosion_t *ex )
350 {
351 	// remove from linked active list
352 	ex->prev->next = ex->next;
353 	ex->next->prev = ex->prev;
354 
355 	// insert into linked free list
356 	ex->next = cl_free_expl;
357 	cl_free_expl = ex;
358 }
359 
360 #if defined(PARTICLESYSTEM)
CL_R_Explode_SP(vec3_t origin,int water)361 void CL_R_Explode_SP (vec3_t origin, int water)
362 {
363 	CL_Explosion_Particle (origin, 50, 25, water);
364 }
365 
CL_G_Explode_SP(vec3_t origin,int water)366 void CL_G_Explode_SP (vec3_t origin, int water)
367 {
368 	CL_Explosion_Particle (origin, 75, 0, water);
369 }
370 #endif
371 /*
372 =================
373 CL_SmokeAndFlash
374 =================
375 */
CL_SmokeAndFlash(vec3_t origin)376 void CL_SmokeAndFlash(vec3_t origin)
377 {
378 	explosion_t	*ex;
379 
380 	ex = CL_AllocExplosion ();
381 	VectorCopy (origin, ex->ent.origin);
382 	ex->type = ex_misc;
383 	ex->frames = 4;
384 	ex->ent.flags = RF_TRANSLUCENT|RF_NOSHADOW;
385 	ex->ent.model = cl_mod_smoke;
386 
387 	ex = CL_AllocExplosion ();
388 	VectorCopy (origin, ex->ent.origin);
389 	ex->type = ex_flash;
390 	ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
391 	ex->frames = 2;
392 	ex->ent.model = cl_mod_flash;
393 }
394 
395 /*
396 =================
397 CL_ParseParticles
398 =================
399 */
CL_ParseParticles(void)400 void CL_ParseParticles (void)
401 {
402 	int		color, count;
403 	vec3_t	pos, dir;
404 
405 	MSG_ReadPos (&net_message, pos);
406 	MSG_ReadDir (&net_message, dir);
407 
408 	color = MSG_ReadByte (&net_message);
409 
410 	count = MSG_ReadByte (&net_message);
411 
412 	CL_ParticleEffect (pos, dir, color, count);
413 }
414 
415 /*
416 =================
417 CL_ParseBeam
418 =================
419 */
CL_ParseBeam(struct model_s * model)420 int CL_ParseBeam (struct model_s *model)
421 {
422 	int		ent;
423 	vec3_t	start, end;
424 	beam_t	*b;
425 	int		i;
426 
427 	ent = MSG_ReadShort (&net_message);
428 
429 	MSG_ReadPos (&net_message, start);
430 	MSG_ReadPos (&net_message, end);
431 
432 // override any beam with the same entity
433 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
434 		if (b->entity == ent)
435 		{
436 			b->entity = ent;
437 			b->model = model;
438 			b->endtime = cl.stime + 200;
439 			VectorCopy (start, b->start);
440 			VectorCopy (end, b->end);
441 			VectorClear (b->offset);
442 			return ent;
443 		}
444 
445 // find a free beam
446 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
447 	{
448 		if (!b->model || b->endtime < cl.stime)
449 		{
450 			b->entity = ent;
451 			b->model = model;
452 			b->endtime = cl.stime + 200;
453 			VectorCopy (start, b->start);
454 			VectorCopy (end, b->end);
455 			VectorClear (b->offset);
456 			return ent;
457 		}
458 	}
459 	Com_Printf ("beam list overflow!\n");
460 	return ent;
461 }
462 
463 /*
464 =================
465 CL_ParseBeam2
466 =================
467 */
CL_ParseBeam2(struct model_s * model)468 int CL_ParseBeam2 (struct model_s *model)
469 {
470 	int		ent;
471 	vec3_t	start, end, offset;
472 	beam_t	*b;
473 	int		i;
474 
475 	ent = MSG_ReadShort (&net_message);
476 
477 	MSG_ReadPos (&net_message, start);
478 	MSG_ReadPos (&net_message, end);
479 	MSG_ReadPos (&net_message, offset);
480 
481 //	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
482 
483 // override any beam with the same entity
484 
485 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
486 		if (b->entity == ent)
487 		{
488 			b->entity = ent;
489 			b->model = model;
490 			b->endtime = cl.stime + 200;
491 			VectorCopy (start, b->start);
492 			VectorCopy (end, b->end);
493 			VectorCopy (offset, b->offset);
494 			return ent;
495 		}
496 
497 // find a free beam
498 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
499 	{
500 		if (!b->model || b->endtime < cl.stime)
501 		{
502 			b->entity = ent;
503 			b->model = model;
504 			b->endtime = cl.stime + 200;
505 			VectorCopy (start, b->start);
506 			VectorCopy (end, b->end);
507 			VectorCopy (offset, b->offset);
508 			return ent;
509 		}
510 	}
511 	Com_Printf ("beam list overflow!\n");
512 	return ent;
513 }
514 
515 // ROGUE
516 /*
517 =================
518 CL_ParsePlayerBeam
519   - adds to the cl_playerbeam array instead of the cl_beams array
520 =================
521 */
CL_ParsePlayerBeam(struct model_s * model)522 int CL_ParsePlayerBeam (struct model_s *model)
523 {
524 	int		ent;
525 	vec3_t		start, end, offset;
526 	beam_t		*b;
527 	int		i;
528 
529 	ent = MSG_ReadShort (&net_message);
530 
531 	MSG_ReadPos (&net_message, start);
532 	MSG_ReadPos (&net_message, end);
533 	// PMM - network optimization
534 	if (model == cl_mod_heatbeam)
535 		VectorSet(offset, 2, 7, -3);
536 	else if (model == cl_mod_monster_heatbeam)
537 	{
538 		model = cl_mod_heatbeam;
539 		VectorSet(offset, 0, 0, 0);
540 	}
541 	else
542 		MSG_ReadPos (&net_message, offset);
543 
544 //	Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
545 
546 // override any beam with the same entity
547 // PMM - For player beams, we only want one per player (entity) so..
548 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
549 	{
550 		if (b->entity == ent)
551 		{
552 			b->entity = ent;
553 			b->model = model;
554 			b->endtime = cl.stime + 200;
555 			VectorCopy (start, b->start);
556 			VectorCopy (end, b->end);
557 			VectorCopy (offset, b->offset);
558 			return ent;
559 		}
560 	}
561 
562 // find a free beam
563 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
564 	{
565 		if (!b->model || b->endtime < cl.stime)
566 		{
567 			b->entity = ent;
568 			b->model = model;
569 			b->endtime = cl.stime + 100;		// PMM - this needs to be 100 to prevent multiple heatbeams
570 			VectorCopy (start, b->start);
571 			VectorCopy (end, b->end);
572 			VectorCopy (offset, b->offset);
573 			return ent;
574 		}
575 	}
576 	Com_Printf ("beam list overflow!\n");
577 	return ent;
578 }
579 //rogue
580 
581 /*
582 =================
583 CL_ParseLightning
584 =================
585 */
586 #if defined(PARTICLESYSTEM)
CL_ParseLightning(float size)587 int CL_ParseLightning (float size)
588 {
589 
590 	vec3_t		start, end;
591 	int		srcEnt, dstEnt;
592 
593 	srcEnt = MSG_ReadShort (&net_message);
594 	dstEnt = MSG_ReadShort (&net_message);
595 
596 	MSG_ReadPos (&net_message, start);
597 	MSG_ReadPos (&net_message, end);
598 
599 	CL_LightningBeam(start, end, srcEnt, dstEnt, size);
600 
601 	return srcEnt;
602 }
603 #else
CL_ParseLightning(struct model_s * model)604 int CL_ParseLightning (struct model_s *model)
605 {
606 	int		srcEnt, destEnt;
607 	vec3_t	start, end;
608 	beam_t	*b;
609 	int		i;
610 
611 	srcEnt = MSG_ReadShort (&net_message);
612 	destEnt = MSG_ReadShort (&net_message);
613 
614 	MSG_ReadPos (&net_message, start);
615 	MSG_ReadPos (&net_message, end);
616 
617 // override any beam with the same source AND destination entities
618 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
619 		if (b->entity == srcEnt && b->dest_entity == destEnt)
620 		{
621 //			Com_Printf("%d: OVERRIDE  %d -> %d\n", cl.time, srcEnt, destEnt);
622 			b->entity = srcEnt;
623 			b->dest_entity = destEnt;
624 			b->model = model;
625 			b->endtime = cl.stime + 200;
626 			VectorCopy (start, b->start);
627 			VectorCopy (end, b->end);
628 			VectorClear (b->offset);
629 			return srcEnt;
630 		}
631 
632 // find a free beam
633 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
634 	{
635 		if (!b->model || b->endtime < cl.stime)
636 		{
637 //			Com_Printf("%d: NORMAL  %d -> %d\n", cl.time, srcEnt, destEnt);
638 			b->entity = srcEnt;
639 			b->dest_entity = destEnt;
640 			b->model = model;
641 			b->endtime = cl.stime + 200;
642 			VectorCopy (start, b->start);
643 			VectorCopy (end, b->end);
644 			VectorClear (b->offset);
645 			return srcEnt;
646 		}
647 	}
648 	Com_Printf ("beam list overflow!\n");
649 	return srcEnt;
650 }
651 #endif
652 
653 /*
654 =================
655 CL_ParseLaser
656 =================
657 */
CL_ParseLaser(int colors)658 void CL_ParseLaser (int colors)
659 {
660 	vec3_t	start;
661 	vec3_t	end;
662 	laser_t	*l;
663 	int		i;
664 
665 	MSG_ReadPos (&net_message, start);
666 	MSG_ReadPos (&net_message, end);
667 
668 	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
669 	{
670 		if (l->endtime < cl.stime)
671 		{
672 			l->ent.flags = RF_TRANSLUCENT | RF_BEAM | RF_NOSHADOW;
673 			VectorCopy (start, l->ent.origin);
674 			VectorCopy (end, l->ent.oldorigin);
675 			l->ent.alpha = 0.30;
676 			l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
677 			l->ent.model = NULL;
678 			l->ent.frame = 4;
679 			l->endtime = cl.stime + 100;
680 			return;
681 		}
682 	}
683 }
684 
685 //=============
686 //ROGUE
CL_ParseSteam(void)687 void CL_ParseSteam (void)
688 {
689 	vec3_t	pos, dir;
690 	int		id, i;
691 	int		r;
692 	int		cnt;
693 	int		color;
694 	int		magnitude;
695 	cl_sustain_t	*s, *free_sustain;
696 
697 	id = MSG_ReadShort (&net_message);		// an id of -1 is an instant effect
698 	if (id != -1) // sustains
699 	{
700 //			Com_Printf ("Sustain effect id %d\n", id);
701 		free_sustain = NULL;
702 		for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
703 		{
704 			if (s->id == 0)
705 			{
706 				free_sustain = s;
707 				break;
708 			}
709 		}
710 		if (free_sustain)
711 		{
712 			s->id = id;
713 			s->count = MSG_ReadByte (&net_message);
714 			MSG_ReadPos (&net_message, s->org);
715 			MSG_ReadDir (&net_message, s->dir);
716 			r = MSG_ReadByte (&net_message);
717 			s->color = r & 0xff;
718 			s->magnitude = MSG_ReadShort (&net_message);
719 			s->endtime = cl.stime + MSG_ReadLong (&net_message);
720 			s->think = CL_ParticleSteamEffect2;
721 			s->thinkinterval = 100;
722 			s->nextthink = cl.stime;
723 		}
724 		else
725 		{
726 //				Com_Printf ("No free sustains!\n");
727 			// FIXME - read the stuff anyway
728 			cnt = MSG_ReadByte (&net_message);
729 			MSG_ReadPos (&net_message, pos);
730 			MSG_ReadDir (&net_message, dir);
731 			r = MSG_ReadByte (&net_message);
732 			magnitude = MSG_ReadShort (&net_message);
733 			magnitude = MSG_ReadLong (&net_message); // really interval
734 		}
735 	}
736 	else // instant
737 	{
738 		cnt = MSG_ReadByte (&net_message);
739 		MSG_ReadPos (&net_message, pos);
740 		MSG_ReadDir (&net_message, dir);
741 		r = MSG_ReadByte (&net_message);
742 		magnitude = MSG_ReadShort (&net_message);
743 		color = r & 0xff;
744 #if defined(PARTICLESYSTEM)
745 		CL_ParticleSteamEffect(pos, dir,
746 		                       color8red(color),
747 				       color8green(color),
748 				       color8blue(color),
749 		                       -20, -20, -20, cnt, magnitude);
750 #else
751 		CL_ParticleSteamEffect(pos, dir, color, cnt, magnitude);
752 #endif
753 //		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
754 	}
755 }
756 
CL_ParseWidow(void)757 void CL_ParseWidow (void)
758 {
759 	vec3_t	pos;
760 	int		id, i;
761 	cl_sustain_t	*s, *free_sustain;
762 
763 	id = MSG_ReadShort (&net_message);
764 
765 	free_sustain = NULL;
766 	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
767 	{
768 		if (s->id == 0)
769 		{
770 			free_sustain = s;
771 			break;
772 		}
773 	}
774 	if (free_sustain)
775 	{
776 		s->id = id;
777 		MSG_ReadPos (&net_message, s->org);
778 		s->endtime = cl.stime + 2100;
779 		s->think = CL_Widowbeamout;
780 		s->thinkinterval = 1;
781 		s->nextthink = cl.stime;
782 	}
783 	else // no free sustains
784 	{
785 		// FIXME - read the stuff anyway
786 		MSG_ReadPos (&net_message, pos);
787 	}
788 }
789 
CL_ParseNuke(void)790 void CL_ParseNuke (void)
791 {
792 	vec3_t	pos;
793 	int		i;
794 	cl_sustain_t	*s, *free_sustain;
795 
796 	free_sustain = NULL;
797 	for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
798 	{
799 		if (s->id == 0)
800 		{
801 			free_sustain = s;
802 			break;
803 		}
804 	}
805 	if (free_sustain)
806 	{
807 		s->id = 21000;
808 		MSG_ReadPos (&net_message, s->org);
809 		s->endtime = cl.stime + 1000;
810 #if defined(PARTICLESYSTEM)
811 		if (cl_nukeblast_enh->value) {
812 			s->think = CL_Nukeblast_Opt;
813 		}
814 		else
815 #endif
816 		s->think = CL_Nukeblast;
817 		s->thinkinterval = 1;
818 		s->nextthink = cl.stime;
819 	}
820 	else // no free sustains
821 	{
822 		// FIXME - read the stuff anyway
823 		MSG_ReadPos (&net_message, pos);
824 	}
825 }
826 
827 //ROGUE
828 //=============
829 
830 /*
831  =================
832  CL_FindTrailPlane
833 
834  Disgusting hack
835  =================
836 */
837 #if !defined(PARTICLESYSTEM)
CL_FindTrailPlane(vec3_t start,vec3_t end,vec3_t dir)838 void CL_FindTrailPlane (vec3_t start, vec3_t end, vec3_t dir)
839 {
840 
841 	trace_t	trace;
842 	vec3_t	vec, point;
843 	float	len;
844 
845 	VectorSubtract(end, start, vec);
846 	len = VectorNormalize(vec);
847 	VectorMA(start, len + 0.5, vec, point);
848 
849 	trace = CM_BoxTrace(start, point, vec3_origin, vec3_origin, 0, MASK_SOLID);
850 	if (trace.allsolid || trace.fraction == 1.0){
851 		VectorClear(dir);
852 		return;
853 	}
854 
855 	VectorCopy(trace.plane.normal, dir);
856 }
857 
858 /*
859  =================
860  CL_FindExplosionPlane
861 
862  Disgusting hack
863  =================
864 */
CL_FindExplosionPlane(vec3_t org,float radius,vec3_t dir)865 void CL_FindExplosionPlane (vec3_t org, float radius, vec3_t dir)
866 {
867 
868 	static vec3_t	planes[6] = {{0, 0, 1},
869 				     {0, 1, 0},
870 				     {1, 0, 0},
871 				     {0, 0, -1},
872 				     {0, -1, 0},
873 				     {-1, 0, 0}};
874 	trace_t		trace;
875 	vec3_t		point;
876 	float		best = 1.0;
877 	int		i;
878 
879 	VectorClear(dir);
880 
881 	for (i = 0; i < 6; i++) {
882 		VectorMA(org, radius, planes[i], point);
883 
884 		trace = CM_BoxTrace(org, point, vec3_origin, vec3_origin, 0, MASK_SOLID);
885 		if (trace.allsolid || trace.fraction == 1.0)
886 			continue;
887 
888 		if (trace.fraction < best){
889 			best = trace.fraction;
890 			VectorCopy(trace.plane.normal, dir);
891 		}
892 	}
893 }
894 #endif
895 
896 /*
897 =================
898 CL_ParseTEnt
899 =================
900 */
901 static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
902 
CL_ParseTEnt(void)903 void CL_ParseTEnt (void)
904 {
905 	int		type;
906 	vec3_t	pos, pos2, dir;
907 	explosion_t	*ex;
908 	int		cnt;
909 	int		color;
910 	int		r;
911 	int		ent;
912 	int		magnitude;
913 #if defined(PARTICLESYSTEM)
914 	int		red,
915 			green,
916 			blue;
917 	int		decalsize = 0;
918 	float		smokesize;
919 	vec3_t		sparkdir;
920 #endif
921 
922 	type = MSG_ReadByte (&net_message);
923 
924 	switch (type)
925 	{
926 	case TE_BLOOD:			// bullet hitting flesh
927 		MSG_ReadPos (&net_message, pos);
928 		MSG_ReadDir (&net_message, dir);
929 #if defined(PARTICLESYSTEM)
930 		CL_BloodHit (pos, dir);
931 #else
932 		CL_ParticleEffect (pos, dir, 0xe8, 60);
933 #endif
934 		break;
935 
936 	case TE_GUNSHOT:			// bullet hitting wall
937 	case TE_SPARKS:
938 #if defined(PARTICLESYSTEM)
939 	case TE_BULLET_SPARKS:
940 		MSG_ReadPos (&net_message, pos);
941 		MSG_ReadDir (&net_message, dir);
942 		if (type == TE_GUNSHOT)
943 			decalsize = 3;
944 		else if (type == TE_SHOTGUN)
945 			decalsize = 4;
946 
947 		if (type == TE_BULLET_SPARKS)
948 			VectorScale(dir, 2, dir);
949 
950 		{
951 			vec3_t color = {255, 125, 10};
952 			CL_ParticleEffectSparks(pos, dir, color, (type == TE_GUNSHOT) ? 5 : 10);
953 		}
954 
955 		if (type != TE_SPARKS)
956 		{
957 			if (cl_gunsmoke->value)
958 				CL_ImpactSmokeEffect(pos, dir, 0.5);
959 			CL_ParticleBulletDecal(pos, dir, decalsize);
960 
961 			// impact sound
962 			cnt = rand()&15;
963 			if (cnt == 1)
964 				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
965 			else if (cnt == 2)
966 				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
967 			else if (cnt == 3)
968 				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
969 		}
970 		break;
971 #else
972 	case TE_BULLET_SPARKS:
973 		MSG_ReadPos (&net_message, pos);
974 		MSG_ReadDir (&net_message, dir);
975 		re.AddDecal(pos, dir, 0, 0, 0, 1.0, 0, 0, 0, 0,
976 		            4 + ((rand()%21*0.05) - 0.5),
977 			    DECAL_BULLET, 0, rand()%361);
978 		if (type == TE_GUNSHOT)
979 			CL_ParticleEffect (pos, dir, 0, 40);
980 		else
981 			CL_ParticleEffect (pos, dir, 0xe0, 6);
982 		if (type != TE_SPARKS)
983 		{
984 			CL_SmokeAndFlash(pos);
985 			// impact sound
986 			cnt = rand()&15;
987 			if (cnt == 1)
988 				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
989 			else if (cnt == 2)
990 				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
991 			else if (cnt == 3)
992 				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
993 		}
994 		break;
995 #endif
996 	case TE_SCREEN_SPARKS:
997 	case TE_SHIELD_SPARKS:
998 		MSG_ReadPos (&net_message, pos);
999 		MSG_ReadDir (&net_message, dir);
1000 		if (type == TE_SCREEN_SPARKS)
1001 			CL_ParticleEffect (pos, dir, 0xd0, 40);
1002 		else
1003 			CL_ParticleEffect (pos, dir, 0xb0, 40);
1004 		//FIXME : replace or remove this sound
1005 		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1006 		break;
1007 
1008 	case TE_SHOTGUN:			// bullet hitting wall
1009 #if defined(PARTICLESYSTEM)
1010 		MSG_ReadPos (&net_message, pos);
1011 		MSG_ReadDir (&net_message, dir);
1012 
1013 		if (type == TE_GUNSHOT) {
1014 			decalsize = 2.5;
1015 			smokesize = 1;
1016 		}
1017 		else if (type == TE_BULLET_SPARKS) {
1018 			decalsize = 3;
1019 			smokesize = 1.25;
1020 		}
1021 		else if (type == TE_SHOTGUN) {
1022 			decalsize = 3.5;
1023 			smokesize = random()*0.75 + 0.25;
1024 		}
1025 
1026 		if (!modType("dday") && !modType("action")) {
1027 			decalsize *= 2;
1028 			smokesize *= 1.5;
1029 		}
1030 
1031 		if (type == TE_BULLET_SPARKS) {
1032 			VectorScale(dir, 1.25 * smokesize, sparkdir);
1033 		}
1034 		else if (type != TE_SPARKS && type != TE_SHOTGUN) {
1035 			VectorScale(dir, 1.1 * smokesize, sparkdir);
1036 			// impact sound
1037 			cnt = rand()&15;
1038 			if (cnt == 1)
1039 				S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
1040 			else if (cnt == 2)
1041 				S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
1042 			else if (cnt == 3)
1043 				S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
1044 		}
1045 		else
1046 			VectorCopy(dir, sparkdir);
1047 
1048 		//adding sparks
1049 		{
1050 			vec3_t color = { 255, 125, 10 };
1051 			CL_ParticleEffectSparks (pos, sparkdir, color, (type == TE_GUNSHOT)? 5 : 10);
1052 		}
1053 
1054 		if (type != TE_SPARKS) {
1055 			VectorNormalize(dir);
1056 			if (cl_gunsmoke->value)
1057 				CL_ImpactSmokeEffect(pos, dir, smokesize);
1058 
1059 			CL_ParticleBulletDecal(pos, dir, decalsize);
1060 		}
1061 		break;
1062 #else
1063 		MSG_ReadPos (&net_message, pos);
1064 		MSG_ReadDir (&net_message, dir);
1065 		re.AddDecal(pos, dir, 0, 0, 0, 1.0, 0, 0, 0, 0,
1066 		            6 + ((rand()%21*0.05) - 0.5),
1067 			    DECAL_BULLET, 0, rand()%361);
1068 		CL_ParticleEffect (pos, dir, 0, 20);
1069 		CL_SmokeAndFlash(pos);
1070 		break;
1071 #endif
1072 	case TE_SPLASH:			// bullet hitting water
1073 		cnt = MSG_ReadByte (&net_message);
1074 		MSG_ReadPos (&net_message, pos);
1075 		MSG_ReadDir (&net_message, dir);
1076 		r = MSG_ReadByte (&net_message);
1077 		if (r > 6)
1078 			color = 0x00;
1079 		else
1080 			color = splash_color[r];
1081 
1082 		if (r == SPLASH_SPARKS)
1083 		{
1084 			CL_ParticleEffect (pos, dir, color, cnt);
1085 			r = rand() & 3;
1086 			if (r == 0)
1087 				S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
1088 			else if (r == 1)
1089 				S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
1090 			else
1091 				S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
1092 		}
1093 #if defined(PARTICLESYSTEM)
1094 		else
1095 			CL_ParticleWaterEffectSplash (pos, dir, color, cnt, r);
1096 #endif
1097 		break;
1098 
1099 	case TE_LASER_SPARKS:
1100 		cnt = MSG_ReadByte (&net_message);
1101 		MSG_ReadPos (&net_message, pos);
1102 		MSG_ReadDir (&net_message, dir);
1103 		color = MSG_ReadByte (&net_message);
1104 		CL_ParticleEffect2 (pos, dir, color, cnt);
1105 		break;
1106 
1107 	// RAFAEL
1108 	case TE_BLUEHYPERBLASTER:
1109 		MSG_ReadPos (&net_message, pos);
1110 		MSG_ReadPos (&net_message, dir);
1111 #if defined(PARTICLESYSTEM)
1112 		CL_BlasterParticles (pos, dir, 40);
1113 #else
1114 		CL_BlasterParticles (pos, dir);
1115 #endif
1116 		break;
1117 
1118 	case TE_BLASTER: // blaster hitting wall
1119 		MSG_ReadPos (&net_message, pos);
1120 		MSG_ReadDir (&net_message, dir);
1121 #if defined(PARTICLESYSTEM)
1122 		if (cl_blaster_color->value == 1) {
1123 			/* give the bolt a red particle glow */
1124 			CL_BlasterParticlesColor(pos, dir, 40, 235, 50, 50, 0, -90, -30);
1125 			if (cl_gunsmoke->value)
1126 				CL_WeapSmokeEffect(pos, dir, 235, 50, 50, 1.0, 0.4f);
1127 			CL_ParticleBlasterColorDecal(pos, dir, 7.5, 235, 50, 50);
1128 		} else if (cl_blaster_color->value == 2) {
1129 			/* give the bolt a green particle glow */
1130 			CL_BlasterParticlesColor(pos, dir, 40, 50, 235, 50, 0, -90, -30);
1131 			if (cl_gunsmoke->value)
1132 				CL_WeapSmokeEffect(pos, dir, 50, 235, 50, 1.0, 0.4f);
1133 			CL_ParticleBlasterColorDecal(pos, dir, 7.5, 50, 235, 50);
1134 		} else if (cl_blaster_color->value == 3) {
1135 			/* give the bolt a blue particle glow */
1136 			CL_BlasterParticlesColor(pos, dir, 40, 50, 50, 255, 0, -90, -30);
1137 			if (cl_gunsmoke->value)
1138 				CL_WeapSmokeEffect(pos, dir, 50, 50, 255, 1.0, 0.4f);
1139 			CL_ParticleBlasterColorDecal(pos, dir, 7.5, 50, 50, 255);
1140 		} else {
1141 			CL_BlasterParticles(pos, dir, 40);
1142 			if (cl_gunsmoke->value)
1143 				CL_WeapSmokeEffect(pos, dir, 255, 150, 50, 1.0, 0.4f);
1144 			CL_ParticleBlasterDecal(pos, dir, 7.5);
1145 		}
1146 
1147 		for (r=0; r<3; r++)
1148 		{
1149 			dir[r]*=10;
1150 			pos[r]+=dir[r];
1151 		}
1152 #else
1153         	re.AddDecal(pos, dir, 1, 0.5, 0, 1.0, 1, 0.5, 0, 1, 4 + ((rand()%21*0.05) - 0.5),
1154 			    DECAL_BLASTER, 0, rand()%361);
1155 		CL_BlasterParticles (pos, dir);
1156 
1157 		ex = CL_AllocExplosion ();
1158 		VectorCopy (pos, ex->ent.origin);
1159 		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
1160 	// PMM - fixed to correct for pitch of 0
1161 		if (dir[0])
1162 			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
1163 		else if (dir[1] > 0)
1164 			ex->ent.angles[1] = 90;
1165 		else if (dir[1] < 0)
1166 			ex->ent.angles[1] = 270;
1167 		else
1168 			ex->ent.angles[1] = 0;
1169 
1170 		ex->type = ex_misc;
1171 		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW;
1172 		ex->light = 150;
1173 		ex->lightcolor[0] = 1;
1174 		ex->lightcolor[1] = 1;
1175 		ex->ent.model = cl_mod_explode;
1176 		ex->frames = 4;
1177 #endif
1178 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1179 		break;
1180 
1181 	case TE_RAILTRAIL:			// railgun effect
1182 		MSG_ReadPos (&net_message, pos);
1183 		MSG_ReadPos (&net_message, pos2);
1184 #if defined(PARTICLESYSTEM)
1185 		CL_RailTrail (pos, pos2);
1186 #else
1187 		CL_FindTrailPlane(pos, pos2, dir);
1188 		CL_RailTrail (pos, pos2);
1189 		re.AddDecal(pos2, dir, 50, 50, 235,
1190 		            1, 1, 1, 1, 1,
1191 			    8, DECAL_RAIL, 0, rand()%361);
1192 #endif
1193 		S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
1194 		break;
1195 
1196 	case TE_EXPLOSION2:
1197 	case TE_GRENADE_EXPLOSION:
1198 	case TE_GRENADE_EXPLOSION_WATER:
1199 		MSG_ReadPos (&net_message, pos);
1200 #if defined(PARTICLESYSTEM)
1201 		#if 0
1202 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1203 			CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1204 			CL_ExplosionParticles(pos, 1.25, type == TE_GRENADE_EXPLOSION_WATER);
1205 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1206 			CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1207 			CL_ExplosionParticles_Old(pos);
1208 		} else {
1209 			ex = CL_AllocExplosion();
1210 			VectorCopy(pos, ex->ent.origin);
1211 			ex->type = ex_poly;
1212 			ex->ent.flags = RF_FULLBRIGHT;
1213 			ex->start = cl.frame.servertime - 100;
1214 			ex->light = 350;
1215 			ex->lightcolor[0] = 1.0;
1216 			ex->lightcolor[1] = 0.5;
1217 			ex->lightcolor[2] = 0.5;
1218 			ex->ent.model = cl_mod_explo4;
1219 			ex->ent.scale = cl_explosion_scale->value;
1220 			ex->frames = 19;
1221 			ex->baseframe = 30;
1222 			ex->ent.angles[1] = rand() % 360;
1223 			CL_Explosion_Decal (pos, 75);
1224 		}
1225 		#else
1226 		if (!cl_explosion->value)
1227 		{
1228 			ex = CL_AllocExplosion ();
1229 			VectorCopy (pos, ex->ent.origin);
1230 			ex->type = ex_poly;
1231 			ex->ent.flags = RF_FULLBRIGHT;
1232 			ex->start = cl.frame.servertime - 100;
1233 			ex->light = 350;
1234 			ex->lightcolor[0] = 1.0;
1235 			ex->lightcolor[1] = 0.5;
1236 			ex->lightcolor[2] = 0.5;
1237 			ex->ent.model = cl_mod_explo4;
1238 			ex->ent.scale = cl_explosion_scale->value;
1239 			ex->frames = 19;
1240 			ex->baseframe = 30;
1241 			ex->ent.angles[1] = rand() % 360;
1242 
1243 			CL_Explosion_Decal (pos, 75);
1244 		}
1245 		else
1246 			CL_G_Explode_SP(pos, type==TE_GRENADE_EXPLOSION_WATER);
1247 		CL_ExplosionParticles (pos,1.25, type==TE_GRENADE_EXPLOSION_WATER);
1248 		#endif
1249 #else
1250 		CL_FindExplosionPlane(pos, 80, dir);
1251 		re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1252 		            56 + ((rand()%21*0.05) - 0.5),
1253                             DECAL_EXPLODE, 0, rand()%361);
1254 		ex = CL_AllocExplosion ();
1255 		VectorCopy (pos, ex->ent.origin);
1256 		ex->type = ex_poly;
1257 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1258 		ex->light = 350;
1259 		ex->lightcolor[0] = 1.0;
1260 		ex->lightcolor[1] = 0.5;
1261 		ex->lightcolor[2] = 0.5;
1262 		ex->ent.model = cl_mod_explo4;
1263 		ex->frames = 19;
1264 		ex->baseframe = 30;
1265 		ex->ent.angles[1] = rand() % 360;
1266 		CL_ExplosionParticles (pos);
1267 #endif
1268 		if (type == TE_GRENADE_EXPLOSION_WATER)
1269 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1270 		else
1271 			S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
1272 		break;
1273 
1274 	// RAFAEL
1275 	case TE_PLASMA_EXPLOSION:
1276 		MSG_ReadPos (&net_message, pos);
1277 #if defined(PARTICLESYSTEM)
1278 		#if 0
1279 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1280 			CL_R_Explode_SP(pos, 0);
1281 			CL_ExplosionParticles(pos, 1, 0);
1282 			CL_Explosion_Sparks (pos, 32);
1283 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1284 			CL_R_Explode_SP(pos, 0);
1285 		} else {
1286 			ex = CL_AllocExplosion();
1287 			VectorCopy(pos, ex->ent.origin);
1288 			ex->type = ex_poly;
1289 			ex->ent.flags = RF_FULLBRIGHT;
1290 			ex->start = cl.frame.servertime - 100;
1291 			ex->light = 350;
1292 			ex->lightcolor[0] = 1.0;
1293 			ex->lightcolor[1] = 0.5;
1294 			ex->lightcolor[2] = 0.5;
1295 			ex->ent.angles[1] = rand() % 360;
1296 			ex->ent.model = cl_mod_explo4;
1297 			ex->ent.scale = cl_explosion_scale->value;
1298 			if (frand() < 0.5)
1299 				ex->baseframe = 15;
1300 			ex->frames = 15;
1301 			CL_Explosion_Decal (pos, 50);
1302 		}
1303 		#else
1304 		if (!cl_explosion->value)
1305 		{
1306 			ex = CL_AllocExplosion ();
1307 			VectorCopy (pos, ex->ent.origin);
1308 			ex->type = ex_poly;
1309 			ex->ent.flags = RF_FULLBRIGHT;
1310 			ex->start = cl.frame.servertime - 100;
1311 			ex->light = 350;
1312 			ex->lightcolor[0] = 1.0;
1313 			ex->lightcolor[1] = 0.5;
1314 			ex->lightcolor[2] = 0.5;
1315 			ex->ent.angles[1] = rand() % 360;
1316 			ex->ent.model = cl_mod_explo4;
1317 			ex->ent.scale = cl_explosion_scale->value;
1318 			if (frand() < 0.5)
1319 				ex->baseframe = 15;
1320 			ex->frames = 15;
1321 
1322 			CL_Explosion_Decal (pos, 50);
1323 		}
1324 		else
1325 			CL_R_Explode_SP(pos, 0);
1326 
1327 		CL_ExplosionParticles (pos, 1, 0);
1328 		#endif
1329 #else
1330 		ex = CL_AllocExplosion ();
1331 		VectorCopy (pos, ex->ent.origin);
1332 		ex->type = ex_poly;
1333 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1334 		ex->light = 350;
1335 		ex->lightcolor[0] = 1.0;
1336 		ex->lightcolor[1] = 0.5;
1337 		ex->lightcolor[2] = 0.5;
1338 		ex->ent.angles[1] = rand() % 360;
1339 		ex->ent.model = cl_mod_explo4;
1340 		if (frand() < 0.5)
1341 			ex->baseframe = 15;
1342 		ex->frames = 15;
1343 		CL_ExplosionParticles (pos);
1344 #endif
1345 		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1346 		break;
1347 
1348 	case TE_EXPLOSION1:
1349 	case TE_EXPLOSION1_BIG:						// PMM
1350 #if defined(PARTICLESYSTEM)
1351 		MSG_ReadPos (&net_message, pos);
1352 		#if 0
1353 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1354 			CL_Explosion_Particle(pos, 100, 0,0);
1355 			CL_ExplosionParticles(pos, 3, 0);
1356 			CL_Explosion_Sparks(pos, 96);
1357 			{
1358 				vec3_t color = {200, 100, 10};
1359 				CL_ParticleEffectSparks(pos, dir, color, 8);
1360 			}
1361 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1362 			CL_Explosion_Particle(pos, 100, 0,0);
1363 			CL_ExplosionParticles_Old(pos);
1364 		} else {
1365 			ex = CL_AllocExplosion();
1366 			VectorCopy(pos, ex->ent.origin);
1367 			ex->type = ex_poly;
1368 			ex->ent.flags = RF_FULLBRIGHT;
1369 			ex->start = cl.frame.servertime - 100;
1370 			ex->light = 350;
1371 			ex->lightcolor[0] = 1.0;
1372 			ex->lightcolor[1] = 0.5;
1373 			ex->lightcolor[2] = 0.5;
1374 			ex->ent.angles[1] = rand() % 360;
1375 			ex->ent.scale = cl_explosion_scale->value;
1376 			ex->ent.model = cl_mod_explo4_big;
1377 			if (frand() < 0.5)
1378 				ex->baseframe = 15;
1379 			ex->frames = 15;
1380 
1381 			CL_Explosion_Decal (pos, 100);
1382 			CL_ExplosionParticles(pos, 3, 0);
1383 		}
1384 		#else
1385 		if (!cl_explosion->value)
1386 		{
1387 
1388 			ex = CL_AllocExplosion ();
1389 			VectorCopy (pos, ex->ent.origin);
1390 			ex->type = ex_poly;
1391 			ex->ent.flags = RF_FULLBRIGHT;
1392 			ex->start = cl.frame.servertime - 100;
1393 			ex->light = 350;
1394 			ex->lightcolor[0] = 1.0;
1395 			ex->lightcolor[1] = 0.5;
1396 			ex->lightcolor[2] = 0.5;
1397 			ex->ent.angles[1] = rand() % 360;
1398 			ex->ent.scale = cl_explosion_scale->value;
1399 			ex->ent.model = cl_mod_explo4_big;
1400 			if (frand() < 0.5)
1401 				ex->baseframe = 15;
1402 			ex->frames = 15;
1403 
1404 			CL_Explosion_Decal (pos, 100);
1405 			CL_ExplosionParticles (pos, 3, 0);
1406 		}
1407 		else
1408 		{
1409 			if (modType("dday"))
1410 			{
1411 				CL_Explosion_Particle (pos, 250, 0, 0);
1412 				CL_ExplosionParticles (pos, 5, 0);
1413 			}
1414 			else
1415 			{
1416 				CL_Explosion_Particle (pos, 100, 0, 0);
1417 				CL_ExplosionParticles (pos, 2, 0);
1418 			}
1419 		}
1420 		#endif
1421 		S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1422 		break;
1423 #endif
1424 	case TE_ROCKET_EXPLOSION:
1425 	case TE_ROCKET_EXPLOSION_WATER:
1426 		MSG_ReadPos(&net_message, pos);
1427 #if defined(PARTICLESYSTEM)
1428 		#if 0
1429 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1430 			CL_Explosion_Particle (pos, 50, 0, 0);
1431 			CL_ExplosionParticles(pos, 1, type==TE_ROCKET_EXPLOSION_WATER);
1432 			CL_Explosion_Sparks(pos, 21);
1433 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1434 			CL_Explosion_Particle (pos, 50, 0, 0);
1435 			CL_ExplosionParticles_Old(pos);
1436 		} else {
1437 			ex = CL_AllocExplosion();
1438 			VectorCopy(pos, ex->ent.origin);
1439 			ex->type = ex_poly;
1440 			ex->ent.flags = RF_FULLBRIGHT;
1441 			ex->start = cl.frame.servertime - 100;
1442 			ex->light = 350;
1443 			ex->lightcolor[0] = 1.0;
1444 			ex->lightcolor[1] = 0.5;
1445 			ex->lightcolor[2] = 0.5;
1446 			ex->ent.angles[1] = rand() % 360;
1447 			ex->ent.model = cl_mod_explo4;
1448 			ex->ent.scale = cl_explosion_scale->value;
1449 			if (frand() < 0.5)
1450 				ex->baseframe = 15;
1451 			ex->frames = 15;
1452 			CL_Explosion_Decal (pos, 50);
1453 
1454 		}
1455 		#else
1456 		if (!cl_explosion->value)
1457 		{
1458 			ex = CL_AllocExplosion ();
1459 			VectorCopy (pos, ex->ent.origin);
1460 			ex->type = ex_poly;
1461 			ex->ent.flags = RF_FULLBRIGHT;
1462 			ex->start = cl.frame.servertime - 100;
1463 			ex->light = 350;
1464 			ex->lightcolor[0] = 1.0;
1465 			ex->lightcolor[1] = 0.5;
1466 			ex->lightcolor[2] = 0.5;
1467 			ex->ent.angles[1] = rand() % 360;
1468 			ex->ent.model = cl_mod_explo4;
1469 			ex->ent.scale = cl_explosion_scale->value;
1470 			if (frand() < 0.5)
1471 				ex->baseframe = 15;
1472 			ex->frames = 15;
1473 
1474 			CL_Explosion_Decal (pos, 50);
1475 		}
1476 		else
1477 			CL_R_Explode_SP(pos, type==TE_ROCKET_EXPLOSION_WATER);
1478 
1479 		CL_ExplosionParticles (pos, 1, type==TE_ROCKET_EXPLOSION_WATER);
1480 		#endif
1481 #else
1482 		CL_FindExplosionPlane(pos, 70, dir);
1483 		re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1484 			    56 + ((rand()%21*0.05) - 0.5),
1485 			    DECAL_EXPLODE, 0, rand()%361);
1486 		ex = CL_AllocExplosion();
1487 		VectorCopy(pos, ex->ent.origin);
1488 		ex->type = ex_poly;
1489 		ex->ent.flags = RF_FULLBRIGHT | RF_NOSHADOW;
1490 		ex->light = 350;
1491 		ex->lightcolor[0] = 1.0;
1492 		ex->lightcolor[1] = 0.5;
1493 		ex->lightcolor[2] = 0.5;
1494 		ex->ent.angles[1] = rand() % 360;
1495 		if (type != TE_EXPLOSION1_BIG)	/* PMM */
1496 			ex->ent.model = cl_mod_explo4;	/* PMM */
1497 		else
1498 			ex->ent.model = cl_mod_explo4_big;
1499 		if (frand() < 0.5)
1500 			ex->baseframe = 15;
1501 		ex->frames = 15;
1502 		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))	/* PMM */
1503 			CL_ExplosionParticles(pos);	/* PMM */
1504 #endif
1505 		if (type == TE_ROCKET_EXPLOSION_WATER)
1506 			S_StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1507 		else
1508 			S_StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1509 		break;
1510 	case TE_EXPLOSION1_NP:						// PMM
1511 		MSG_ReadPos (&net_message, pos);
1512 #if defined(PARTICLESYSTEM)
1513 		#if 0
1514 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1515 			CL_R_Explode_SP(pos, 0);
1516 			CL_ExplosionParticles (pos, 0.6666666, 0);
1517 			CL_Explosion_Sparks(pos, 32);	/* PMM */
1518 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1519 			CL_R_Explode_SP(pos, type==TE_ROCKET_EXPLOSION_WATER);
1520 			CL_ExplosionParticles_Old(pos);
1521 		} else {
1522 			ex = CL_AllocExplosion();
1523 			VectorCopy(pos, ex->ent.origin);
1524 			ex->type = ex_poly;
1525 			ex->ent.flags = RF_FULLBRIGHT;
1526 			ex->start = cl.frame.servertime - 100;
1527 			ex->light = 350;
1528 			ex->lightcolor[0] = 1.0;
1529 			ex->lightcolor[1] = 0.5;
1530 			ex->lightcolor[2] = 0.5;
1531 			ex->ent.angles[1] = rand() % 360;
1532 			ex->ent.model = cl_mod_explo4;
1533 			ex->ent.scale = cl_explosion_scale->value;
1534 			if (frand() < 0.5)
1535 				ex->baseframe = 15;
1536 			ex->frames = 15;
1537 			CL_Explosion_Decal (pos, 65);
1538 
1539 		}
1540 		#else
1541 		if (!cl_explosion->value)
1542 		{
1543 			ex = CL_AllocExplosion ();
1544 			VectorCopy (pos, ex->ent.origin);
1545 			ex->type = ex_poly;
1546 			ex->ent.flags = RF_FULLBRIGHT;
1547 			ex->start = cl.frame.servertime - 100;
1548 			ex->light = 350;
1549 			ex->lightcolor[0] = 1.0;
1550 			ex->lightcolor[1] = 0.5;
1551 			ex->lightcolor[2] = 0.5;
1552 			ex->ent.angles[1] = rand() % 360;
1553 			ex->ent.model = cl_mod_explo4;
1554 			ex->ent.scale = cl_explosion_scale->value;
1555 			if (frand() < 0.5)
1556 				ex->baseframe = 15;
1557 			ex->frames = 15;
1558 
1559 			CL_Explosion_Decal (pos, 65);
1560 		}
1561 		else
1562 			CL_Explosion_Particle (pos, 50, 0, 0);
1563 
1564 		CL_ExplosionParticles (pos, 0.6666666, 0);
1565 		#endif
1566 #else
1567 		CL_FindExplosionPlane(pos, 80, dir);
1568 		re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1569 			    56 + ((rand()%21*0.05) - 0.5),
1570 			    DECAL_EXPLODE, 0, rand()%361);
1571 		ex = CL_AllocExplosion ();
1572 		VectorCopy (pos, ex->ent.origin);
1573 		ex->type = ex_poly;
1574 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1575 		ex->light = 350;
1576 		ex->lightcolor[0] = 1.0;
1577 		ex->lightcolor[1] = 0.5;
1578 		ex->lightcolor[2] = 0.5;
1579 		ex->ent.angles[1] = rand() % 360;
1580 		if (type != TE_EXPLOSION1_BIG)				// PMM
1581 			ex->ent.model = cl_mod_explo4;			// PMM
1582 		else
1583 			ex->ent.model = cl_mod_explo4_big;
1584 		if (frand() < 0.5)
1585 			ex->baseframe = 15;
1586 		ex->frames = 15;
1587 		if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP))		// PMM
1588 			CL_ExplosionParticles (pos); // PMM
1589 #endif
1590 		if (type == TE_ROCKET_EXPLOSION_WATER)
1591 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1592 		else
1593 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1594 		break;
1595 
1596 	case TE_BFG_EXPLOSION:
1597 		MSG_ReadPos (&net_message, pos);
1598 #if defined(PARTICLESYSTEM)
1599 		#if 1
1600 		CL_BFGExplosionParticles_2(pos);
1601 		#else
1602 		ex = CL_AllocExplosion ();
1603 		VectorCopy (pos, ex->ent.origin);
1604 		ex->type = ex_poly;
1605 		ex->ent.flags = RF_FULLBRIGHT;
1606 		ex->start = cl.frame.servertime - 100;
1607 		ex->light = 350;
1608 		ex->lightcolor[0] = 0.0;
1609 		ex->lightcolor[1] = 1.0;
1610 		ex->lightcolor[2] = 0.0;
1611 		ex->ent.model = cl_mod_bfg_explo;
1612 		ex->ent.flags |= RF_TRANSLUCENT | RF_TRANS_ADDITIVE;
1613 		ex->ent.alpha = 0.9999;
1614 		ex->frames = 4;
1615 		ex->ent.scale = 1;
1616 		#endif
1617 #else
1618 		ex = CL_AllocExplosion ();
1619 		VectorCopy (pos, ex->ent.origin);
1620 		ex->type = ex_poly;
1621 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1622 		ex->light = 350;
1623 		ex->lightcolor[0] = 0.0;
1624 		ex->lightcolor[1] = 1.0;
1625 		ex->lightcolor[2] = 0.0;
1626 		ex->ent.model = cl_mod_bfg_explo;
1627 		ex->ent.flags |= RF_TRANSLUCENT|RF_NOSHADOW;
1628 		ex->ent.alpha = 0.30;
1629 		ex->frames = 4;
1630 #endif
1631 		break;
1632 
1633 	case TE_BFG_BIGEXPLOSION:
1634 		MSG_ReadPos (&net_message, pos);
1635 		CL_BFGExplosionParticles (pos);
1636 #if defined(PARTICLESYSTEM)
1637 		CL_Explosion_Decal (pos, 75);
1638 #else
1639 		CL_FindExplosionPlane(pos, 96, dir);
1640 		re.AddDecal(pos, dir, 0.1, 0.1, 0.1, 1, 0.1, 0.1, 0.1, 1,
1641 		            60,
1642 		            DECAL_BFG, 0, rand()%361);
1643 #endif
1644 		break;
1645 
1646 	case TE_BFG_LASER:
1647 		CL_ParseLaser (0xd0d1d2d3);
1648 		break;
1649 
1650 	case TE_BUBBLETRAIL:
1651 		MSG_ReadPos (&net_message, pos);
1652 		MSG_ReadPos (&net_message, pos2);
1653 		CL_BubbleTrail (pos, pos2);
1654 		break;
1655 
1656 	case TE_PARASITE_ATTACK:
1657 	case TE_MEDIC_CABLE_ATTACK:
1658 		ent = CL_ParseBeam (cl_mod_parasite_segment);
1659 		break;
1660 
1661 	case TE_BOSSTPORT:			// boss teleporting to station
1662 		MSG_ReadPos (&net_message, pos);
1663 		CL_BigTeleportParticles (pos);
1664 		S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
1665 		break;
1666 
1667 	case TE_GRAPPLE_CABLE:
1668 		ent = CL_ParseBeam2 (cl_mod_grapple_cable);
1669 		break;
1670 
1671 	// RAFAEL
1672 	case TE_WELDING_SPARKS:
1673 		cnt = MSG_ReadByte (&net_message);
1674 		MSG_ReadPos (&net_message, pos);
1675 		MSG_ReadDir (&net_message, dir);
1676 		color = MSG_ReadByte (&net_message);
1677 #if defined(PARTICLESYSTEM)
1678 		{
1679 			vec3_t	sparkcolor = {
1680 			                       color8red(color),
1681 					       color8green(color),
1682 					       color8blue(color)
1683 					     };
1684 
1685 			CL_ParticleEffectSparks(pos, dir, sparkcolor, 40);
1686 		}
1687 #else
1688 		CL_ParticleEffect2 (pos, dir, color, cnt);
1689 
1690 		ex = CL_AllocExplosion ();
1691 		VectorCopy (pos, ex->ent.origin);
1692 		ex->type = ex_flash;
1693 		// note to self
1694 		// we need a better no draw flag
1695 		ex->ent.flags = RF_BEAM|RF_NOSHADOW;
1696 		ex->light = 100 + (rand()%75);
1697 		ex->lightcolor[0] = 1.0;
1698 		ex->lightcolor[1] = 1.0;
1699 		ex->lightcolor[2] = 0.3;
1700 		ex->ent.model = cl_mod_flash;
1701 		ex->frames = 2;
1702 #endif
1703 		break;
1704 
1705 	case TE_GREENBLOOD:
1706 		MSG_ReadPos (&net_message, pos);
1707 		MSG_ReadDir (&net_message, dir);
1708 #if defined(PARTICLESYSTEM)
1709 		#if 0
1710 		CL_GreenBloodHit(pos, dir);
1711 		#else
1712 		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
1713 		#endif
1714 #else
1715 		CL_ParticleEffect2 (pos, dir, 0xdf, 30);
1716 #endif
1717 		break;
1718 
1719 	// RAFAEL
1720 	case TE_TUNNEL_SPARKS:
1721 		cnt = MSG_ReadByte (&net_message);
1722 		MSG_ReadPos (&net_message, pos);
1723 		MSG_ReadDir (&net_message, dir);
1724 		color = MSG_ReadByte (&net_message);
1725 		CL_ParticleEffect3 (pos, dir, color, cnt);
1726 		break;
1727 
1728 //=============
1729 //PGM
1730 		// PMM -following code integrated for flechette (different color)
1731 	case TE_BLASTER2:			// green blaster hitting wall
1732 	case TE_FLECHETTE:			// flechette
1733 		MSG_ReadPos (&net_message, pos);
1734 		MSG_ReadDir (&net_message, dir);
1735 #if defined(PARTICLESYSTEM)
1736 		#if 1
1737 		if (type == TE_BLASTER2) {
1738 			CL_BlasterParticlesColor (pos, dir, 40, 50, 235, 50, -10, 0, -10);
1739 			red=50;
1740 			green=235;
1741 			blue=50;
1742 		}
1743 		else if (type == TE_BLUEHYPERBLASTER) {
1744 			CL_BlasterParticlesColor (pos, dir, 40, 50, 50, 235, -10, 0, -10);
1745 			red=50;
1746 			green=50;
1747 			blue=235;
1748 		}
1749 		else {
1750  			CL_BlasterParticlesColor (pos, dir, 40, 100, 100, 195, -10, 0, -10);
1751 			red=100;
1752 			green=100;
1753 			blue=195;
1754 		}
1755 		CL_ParticleBlasterColorDecal(pos, dir, 7.5, red, green, blue);
1756 		#else
1757 		CL_BlasterParticlesColor(pos, dir, 40, 50, 50, 235, 0, -90, -30);
1758 		#endif
1759 #else
1760 		// PMM
1761 		if (type == TE_BLASTER2)
1762 			CL_BlasterParticles2 (pos, dir, 0xd0);
1763 		else
1764 			CL_BlasterParticles2 (pos, dir, 0x6f); // 75
1765         	re.AddDecal(pos, dir, 1, 0.5, 0, 1, 1, 0.5, 0, 1, 4,
1766 			    DECAL_BLASTER, 0, 0);
1767 		ex = CL_AllocExplosion ();
1768 		VectorCopy (pos, ex->ent.origin);
1769 		ex->ent.angles[0] = acos(dir[2])/M_PI*180;
1770 	// PMM - fixed to correct for pitch of 0
1771 		if (dir[0])
1772 			ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
1773 		else if (dir[1] > 0)
1774 			ex->ent.angles[1] = 90;
1775 		else if (dir[1] < 0)
1776 			ex->ent.angles[1] = 270;
1777 		else
1778 			ex->ent.angles[1] = 0;
1779 
1780 		ex->type = ex_misc;
1781 		ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT|RF_NOSHADOW;
1782 
1783 		// PMM
1784 		if (type == TE_BLASTER2)
1785 			ex->ent.skinnum = 1;
1786 		else // flechette
1787 			ex->ent.skinnum = 2;
1788 
1789 		ex->light = 150;
1790 		// PMM
1791 		if (type == TE_BLASTER2)
1792 			ex->lightcolor[1] = 1;
1793 		else // flechette
1794 		{
1795 			ex->lightcolor[0] = 0.19;
1796 			ex->lightcolor[1] = 0.41;
1797 			ex->lightcolor[2] = 0.75;
1798 		}
1799 		ex->ent.model = cl_mod_explode;
1800 		ex->frames = 4;
1801 #endif
1802 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1803 		break;
1804 
1805 
1806 	case TE_LIGHTNING:
1807 #if defined(PARTICLESYSTEM)
1808 		ent = CL_ParseLightning (10);
1809 #else
1810 		ent = CL_ParseLightning (cl_mod_lightning);
1811 #endif
1812 		S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
1813 		break;
1814 
1815 	case TE_DEBUGTRAIL:
1816 		MSG_ReadPos (&net_message, pos);
1817 		MSG_ReadPos (&net_message, pos2);
1818 		CL_DebugTrail (pos, pos2);
1819 		break;
1820 
1821 	case TE_PLAIN_EXPLOSION:
1822 		MSG_ReadPos (&net_message, pos);
1823 #if defined(PARTICLESYSTEM)
1824 		#if 0
1825 		if (cl_explosion->value == 4 || cl_explosion->value == 3) {
1826 			CL_Explosion_Particle(pos, 50, true, true);
1827 			CL_ExplosionParticles(pos, 0.6666666, 0);
1828 			CL_Explosion_Sparks(pos, 21);
1829 		} else if (cl_explosion->value == 2 || cl_explosion->value == 1) {
1830 			CL_Explosion_Particle(pos, 50, true, true);
1831 			CL_ExplosionParticles_Old(pos);
1832 		} else {
1833 			ex = CL_AllocExplosion();
1834 			VectorCopy(pos, ex->ent.origin);
1835 			ex->type = ex_poly;
1836 			ex->ent.flags = RF_FULLBRIGHT | RF_NOSHADOW;
1837 			ex->start = cl.frame.servertime - 100;
1838 			ex->light = 350;
1839 			ex->lightcolor[0] = 1.0;
1840 			ex->lightcolor[1] = 0.5;
1841 			ex->lightcolor[2] = 0.5;
1842 			ex->ent.angles[1] = rand() % 360;
1843 			ex->ent.model = cl_mod_explo4;
1844 			if (frand() < 0.5)
1845 				ex->baseframe = 15;
1846 			ex->frames = 15;
1847 		}
1848 		#else
1849 		ex = CL_AllocExplosion ();
1850 		VectorCopy (pos, ex->ent.origin);
1851 		ex->type = ex_poly;
1852 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1853 		ex->light = 350;
1854 		ex->lightcolor[0] = 1.0;
1855 		ex->lightcolor[1] = 0.5;
1856 		ex->lightcolor[2] = 0.5;
1857 		ex->ent.angles[1] = rand() % 360;
1858 		ex->ent.model = cl_mod_explo4;
1859 		if (frand() < 0.5)
1860 			ex->baseframe = 15;
1861 		ex->frames = 15;
1862 		#endif
1863 #else
1864 		CL_FindExplosionPlane(pos, 70, dir);
1865 		re.AddDecal(pos, dir, 1, 0.7, 0, 0.85, 0, 0, 0, 0,
1866 			    56 + ((rand()%21*0.05) - 0.5),
1867 			    DECAL_EXPLODE, 0, rand()%361);
1868 		ex = CL_AllocExplosion ();
1869 		VectorCopy (pos, ex->ent.origin);
1870 		ex->type = ex_poly;
1871 		ex->ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
1872 		ex->light = 350;
1873 		ex->lightcolor[0] = 1.0;
1874 		ex->lightcolor[1] = 0.5;
1875 		ex->lightcolor[2] = 0.5;
1876 		ex->ent.angles[1] = rand() % 360;
1877 		ex->ent.model = cl_mod_explo4;
1878 		if (frand() < 0.5)
1879 			ex->baseframe = 15;
1880 		ex->frames = 15;
1881 #endif
1882 		if (type == TE_ROCKET_EXPLOSION_WATER)
1883 			S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
1884 		else
1885 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
1886 		break;
1887 
1888 	case TE_FLASHLIGHT:
1889 		MSG_ReadPos(&net_message, pos);
1890 		ent = MSG_ReadShort(&net_message);
1891 		CL_Flashlight(ent, pos);
1892 		break;
1893 
1894 	case TE_FORCEWALL:
1895 		MSG_ReadPos(&net_message, pos);
1896 		MSG_ReadPos(&net_message, pos2);
1897 		color = MSG_ReadByte (&net_message);
1898 		CL_ForceWall(pos, pos2, color);
1899 		break;
1900 
1901 	case TE_HEATBEAM:
1902 		ent = CL_ParsePlayerBeam (cl_mod_heatbeam);
1903 		break;
1904 
1905 	case TE_MONSTER_HEATBEAM:
1906 		ent = CL_ParsePlayerBeam (cl_mod_monster_heatbeam);
1907 		break;
1908 
1909 	case TE_HEATBEAM_SPARKS:
1910 		cnt = 50;
1911 		MSG_ReadPos (&net_message, pos);
1912 		MSG_ReadDir (&net_message, dir);
1913 		r = 8;
1914 		magnitude = 60;
1915 		color = r & 0xff;
1916 #if defined(PARTICLESYSTEM)
1917 		CL_ParticleSteamEffect(pos, dir, 240, 240, 240, -20, -20, -20, cnt, magnitude);
1918 #else
1919 		CL_ParticleSteamEffect(pos, dir, color, cnt, magnitude);
1920 #endif
1921 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1922 		break;
1923 
1924 	case TE_HEATBEAM_STEAM:
1925 		cnt = 20;
1926 		MSG_ReadPos (&net_message, pos);
1927 		MSG_ReadDir (&net_message, dir);
1928 		magnitude = 60;
1929 		color = 0xe0;
1930 #if defined(PARTICLESYSTEM)
1931 		CL_ParticleSteamEffect(pos, dir, 255, 150, 50, 0, -90, -30, cnt, magnitude);
1932 		CL_ParticleBlasterDecal(pos, dir, 7.5);
1933 #else
1934 		CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
1935 #endif
1936 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1937 		break;
1938 
1939 	case TE_STEAM:
1940 		CL_ParseSteam();
1941 		break;
1942 
1943 	case TE_BUBBLETRAIL2:
1944 //		cnt = MSG_ReadByte (&net_message);
1945 		cnt = 8;
1946 		MSG_ReadPos (&net_message, pos);
1947 		MSG_ReadPos (&net_message, pos2);
1948 		CL_BubbleTrail2 (pos, pos2, cnt);
1949 		S_StartSound (pos,  0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1950 		break;
1951 
1952 	case TE_MOREBLOOD:
1953 		MSG_ReadPos (&net_message, pos);
1954 		MSG_ReadDir (&net_message, dir);
1955 		CL_ParticleEffect (pos, dir, 0xe8, 250);
1956 		break;
1957 
1958 	case TE_CHAINFIST_SMOKE:
1959 		dir[0]=0; dir[1]=0; dir[2]=1;
1960 		MSG_ReadPos(&net_message, pos);
1961 #if defined(PARTICLESYSTEM)
1962 		CL_ParticleSmokeEffect(pos, dir, 25, 1);
1963 #else
1964 		CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
1965 #endif
1966 		break;
1967 
1968 	case TE_ELECTRIC_SPARKS:
1969 		MSG_ReadPos (&net_message, pos);
1970 		MSG_ReadDir (&net_message, dir);
1971 //		CL_ParticleEffect (pos, dir, 109, 40);
1972 #if defined(PARTICLESYSTEM)
1973 		CL_ElectricParticles(pos, dir, 40);
1974 #else
1975 		CL_ParticleEffect (pos, dir, 0x75, 40);
1976 #endif
1977 		//FIXME : replace or remove this sound
1978 		S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
1979 		break;
1980 
1981 	case TE_TRACKER_EXPLOSION:
1982 		MSG_ReadPos (&net_message, pos);
1983 		CL_ColorFlash (pos, 0, 150, -1, -1, -1);
1984 		#if 1
1985 		CL_ColorExplosionParticles(pos, 0, 1);
1986 		#else
1987 		CL_Tracker_Explode (pos);
1988 		#endif
1989 		S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
1990 		break;
1991 
1992 	case TE_TELEPORT_EFFECT:
1993 	case TE_DBALL_GOAL:
1994 		MSG_ReadPos (&net_message, pos);
1995 		CL_TeleportParticles (pos);
1996 		break;
1997 
1998 	case TE_WIDOWBEAMOUT:
1999 		CL_ParseWidow ();
2000 		break;
2001 
2002 	case TE_NUKEBLAST:
2003 		CL_ParseNuke ();
2004 		break;
2005 
2006 	case TE_WIDOWSPLASH:
2007 		MSG_ReadPos (&net_message, pos);
2008 		CL_WidowSplash (pos);
2009 		break;
2010 
2011 	//NEW CUSTOM TEMP EVENTS
2012 
2013 #if defined(PARTICLESYSTEM)
2014 	case TE_LIGHTNINGFLARE: //-psychospaz
2015 		{
2016 			int num, entity;
2017 
2018 			entity = MSG_ReadShort (&net_message);
2019 			num = MSG_ReadShort (&net_message);
2020 			MSG_ReadPos (&net_message, pos);
2021 
2022 			//double up for opacity endurance
2023 			CL_LightningFlare(pos, entity, 2*num);
2024 			CL_LightningFlare(pos, entity, 2*num+1);
2025 		}
2026 		break;
2027 	case TE_SMOKEPUFF:
2028 		{
2029 			float size;
2030 
2031 			MSG_ReadPos (&net_message, pos);
2032 			MSG_ReadPos (&net_message, dir);
2033 			size = MSG_ReadFloat(&net_message);
2034 
2035 			CL_ParticleSmokeEffect (pos, dir, size, 1);
2036 		}
2037 		break;
2038 	case TE_IMPACTMARK:
2039 		{
2040 			float	size;
2041 			int	flags;
2042 
2043 			MSG_ReadPos (&net_message, pos);
2044 			MSG_ReadPos (&net_message, dir);
2045 			size = MSG_ReadFloat(&net_message);
2046 			flags = MSG_ReadLong (&net_message);
2047 
2048 			CL_ImpactMark (pos, dir, size, flags, particle_impact);
2049 		}
2050 		break;
2051 	case TE_FOOTPRINT:
2052 		{
2053 			float size;
2054 			vec3_t color, angle;
2055 
2056 			MSG_ReadPos (&net_message, pos);
2057 			MSG_ReadPos (&net_message, dir);
2058 			MSG_ReadPos (&net_message, color);
2059 			size = MSG_ReadFloat(&net_message);
2060 
2061 			angle[0] = anglemod(dir[0] + 180);
2062 			angle[1] = anglemod(dir[1]);
2063 			angle[2] = anglemod(dir[2]);
2064 
2065 			CL_ParticleFootPrint (pos, angle, size, color);
2066 		}
2067 		break;
2068 	case TE_FLAMEBURST:
2069 		{
2070 			float size;
2071 
2072 			MSG_ReadPos (&net_message, pos);
2073 			size = MSG_ReadFloat(&net_message);
2074 
2075 			CL_FlameBurst (pos, size);
2076 		}
2077 		break;
2078 	case TE_DISRUPTOR_EXPLOSION:
2079 		{
2080 			float	size;
2081 
2082 			MSG_ReadPos (&net_message, pos);
2083 			size = MSG_ReadFloat(&net_message);
2084 
2085 			CL_Disruptor_Explosion_Particle (pos, size);
2086 
2087 			S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
2088 		}
2089 		break;
2090 	case TE_DISINTEGRATE:
2091 		{
2092 			ent = MSG_ReadByte(&net_message);
2093 			MSG_ReadPos (&net_message, pos);
2094 			CL_Disintegrate (pos, ent);
2095 		}
2096 		break;
2097 #endif
2098 //PGM
2099 //==============
2100 
2101 	default:
2102 		Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
2103 	}
2104 }
2105 
2106 /*
2107 =================
2108 CL_AddBeams
2109 =================
2110 */
2111 extern cvar_t  *hand;
2112 /* Knightmare- backup of client angles */
2113 extern vec3_t	old_viewangles;
CL_AddBeams(void)2114 void CL_AddBeams (void)
2115 {
2116 	int			i,j;
2117 	beam_t		*b;
2118 	vec3_t		dist, org;
2119 	float		d;
2120 	entity_t	ent;
2121 	float		yaw, pitch;
2122 	float		forward;
2123 	float		len, steps;
2124 	float		model_length;
2125 
2126 	/* Knightmare added */
2127 	frame_t        *oldframe;
2128 	player_state_t *ps, *ops;
2129 	qboolean	firstperson, chasecam;
2130 	int		handmult;
2131 	vec3_t		thirdp_grapple_offset;
2132 	vec3_t		grapple_offset_dir;
2133 
2134 	/* Knightmare- chasecam grapple offset stuff */
2135 	if (hand) {
2136 		if (hand->value == 2)
2137 			handmult = 1;
2138 		else if (hand->value == 1)
2139 			handmult = -1;
2140 		else
2141 			handmult = 1;
2142 	} else
2143 		handmult = 1;
2144 	VectorSet(thirdp_grapple_offset, 6, 16, 16);
2145 	/* end Knightmare */
2146 
2147 // update beams
2148 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
2149 	{
2150 		if (!b->model || b->endtime < cl.stime)
2151 			continue;
2152 
2153 		/* Knightmare- */
2154 		firstperson = ((b->entity == cl.playernum + 1) && !cl_3dcam->value);
2155 		chasecam = ((b->entity == cl.playernum + 1) && cl_3dcam->value);
2156 
2157 		// if coming from the player, update the start position
2158 		if (firstperson) {// entity 0 is the world
2159 			VectorCopy (cl.refdef.vieworg, b->start);
2160 			b->start[2] -= 22;	// adjust for view height
2161 		} else if (chasecam) {
2162 			vec3_t		f, r, u;
2163 
2164 			ps = &cl.frame.playerstate;
2165 			j = (cl.frame.serverframe - 1) & UPDATE_MASK;
2166 			oldframe = &cl.frames[j];
2167 			if (oldframe->serverframe != cl.frame.serverframe - 1 || !oldframe->valid)
2168 				oldframe = &cl.frame;
2169 			ops = &oldframe->playerstate;
2170 
2171 			AngleVectors(old_viewangles, f, r, u);
2172 			VectorClear(grapple_offset_dir);
2173 			for (j = 0; j < 3; j++) {
2174 				grapple_offset_dir[j] += f[j] * thirdp_grapple_offset[1];
2175 				grapple_offset_dir[j] += r[j] * thirdp_grapple_offset[0] * handmult;
2176 				grapple_offset_dir[j] += u[j] * (-thirdp_grapple_offset[2]);
2177 			}
2178 
2179 			for (j = 0; j < 3; j++)
2180 				b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j]
2181 				    + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j])
2182 				    + grapple_offset_dir[j];
2183 		}
2184 		if (chasecam)
2185 			VectorCopy(b->start, org);
2186 		else
2187 			VectorAdd (b->start, b->offset, org);
2188 
2189 	// calculate pitch and yaw
2190 		VectorSubtract (b->end, org, dist);
2191 
2192 		if (dist[1] == 0 && dist[0] == 0)
2193 		{
2194 			yaw = 0;
2195 			if (dist[2] > 0)
2196 				pitch = 90;
2197 			else
2198 				pitch = 270;
2199 		}
2200 		else
2201 		{
2202 	// PMM - fixed to correct for pitch of 0
2203 			if (dist[0])
2204 				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
2205 			else if (dist[1] > 0)
2206 				yaw = 90;
2207 			else
2208 				yaw = 270;
2209 			if (yaw < 0)
2210 				yaw += 360;
2211 
2212 			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
2213 			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
2214 			if (pitch < 0)
2215 				pitch += 360.0;
2216 		}
2217 
2218 	// add new entities for the beams
2219 		d = VectorNormalize(dist);
2220 
2221 		memset (&ent, 0, sizeof(ent));
2222 		if (b->model == cl_mod_lightning)
2223 		{
2224 			model_length = 35.0;
2225 			d-= 20.0;  // correction so it doesn't end in middle of tesla
2226 		}
2227 		else
2228 		{
2229 			model_length = 30.0;
2230 		}
2231 		steps = ceil(d/model_length);
2232 		len = (d-model_length)/(steps-1);
2233 
2234 		// PMM - special case for lightning model .. if the real length is shorter than the model,
2235 		// flip it around & draw it from the end to the start.  This prevents the model from going
2236 		// through the tesla mine (instead it goes through the target)
2237 		if ((b->model == cl_mod_lightning) && (d <= model_length))
2238 		{
2239 //			Com_Printf ("special case\n");
2240 			VectorCopy (b->end, ent.origin);
2241 			// offset to push beam outside of tesla model (negative because dist is from end to start
2242 			// for this beam)
2243 //			for (j=0 ; j<3 ; j++)
2244 //				ent.origin[j] -= dist[j]*10.0;
2245 			ent.model = b->model;
2246 			ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2247 			ent.angles[0] = pitch;
2248 			ent.angles[1] = yaw;
2249 			ent.angles[2] = rand()%360;
2250 			V_AddEntity (&ent);
2251 			return;
2252 		}
2253 		while (d > 0)
2254 		{
2255 			VectorCopy (org, ent.origin);
2256 			ent.model = b->model;
2257 			if (b->model == cl_mod_lightning)
2258 			{
2259 				ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2260 				ent.angles[0] = -pitch;
2261 				ent.angles[1] = yaw + 180.0;
2262 				ent.angles[2] = rand()%360;
2263 			}
2264 			else
2265 			{
2266 				ent.angles[0] = pitch;
2267 				ent.angles[1] = yaw;
2268 				ent.angles[2] = rand()%360;
2269 			}
2270 
2271 //			Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
2272 			ent.flags |= RF_NOSHADOW;
2273 			V_AddEntity (&ent);
2274 
2275 			for (j=0 ; j<3 ; j++)
2276 				org[j] += dist[j]*len;
2277 			d -= model_length;
2278 		}
2279 	}
2280 }
2281 
2282 
2283 /*
2284 =================
2285 ROGUE - draw player locked beams
2286 CL_AddPlayerBeams
2287 =================
2288 */
CL_AddPlayerBeams(void)2289 void CL_AddPlayerBeams (void)
2290 {
2291 	int		i,j;
2292 	beam_t		*b;
2293 	vec3_t		dist, org;
2294 	float		d;
2295 	entity_t	ent;
2296 	float		yaw, pitch;
2297 	float		forward;
2298 	float		len, steps;
2299 	int		framenum = 0;
2300 	float		model_length;
2301 
2302 	float		hand_multiplier;
2303 	frame_t		*oldframe;
2304 	player_state_t	*ps, *ops;
2305 	/* Knightmare-  */
2306 	qboolean	firstperson, chasecam;
2307 	int		newhandmult;
2308 	vec3_t		thirdp_pbeam_offset;
2309 	vec3_t		pbeam_offset_dir;
2310 
2311 //PMM
2312 	if (hand)
2313 	{
2314 		if (hand->value == 2)
2315 			hand_multiplier = 0;
2316 		else if (hand->value == 1)
2317 			hand_multiplier = -1;
2318 		else
2319 			hand_multiplier = 1;
2320 	}
2321 	else
2322 	{
2323 		hand_multiplier = 1;
2324 	}
2325 //PMM
2326 	/* Knightmare- chasecam beam offset stuff */
2327 	newhandmult = hand_multiplier;
2328 	if (newhandmult == 0)
2329 		newhandmult = 1;
2330 
2331 	VectorSet(thirdp_pbeam_offset, 6.5, 0, 12);
2332 	/* end Knightmare */
2333 
2334 // update beams
2335 	for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
2336 	{
2337 		vec3_t		f,r,u;
2338 
2339 		if (!b->model || b->endtime < cl.stime)
2340 			continue;
2341 
2342 		firstperson = ((b->entity == cl.playernum + 1) && !cl_3dcam->value);
2343 		chasecam = ((b->entity == cl.playernum + 1) && cl_3dcam->value);
2344 
2345 		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
2346 		{
2347 
2348 			// if coming from the player, update the start position
2349 			if (firstperson || chasecam)	// entity 0 is the world
2350 			{
2351 				// set up gun position
2352 				// code straight out of CL_AddViewWeapon
2353 				ps = &cl.frame.playerstate;
2354 				j = (cl.frame.serverframe - 1) & UPDATE_MASK;
2355 				oldframe = &cl.frames[j];
2356 				if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
2357 					oldframe = &cl.frame;		// previous frame was dropped or involid
2358 				ops = &oldframe->playerstate;
2359 				/* Knightmare- lerp for chasecam mode */
2360 				if (chasecam) {	/* Knightmare- use player's original viewangles */
2361 					AngleVectors(old_viewangles, f, r, u);
2362 					VectorClear(pbeam_offset_dir);
2363 					for (j = 0; j < 3; j++) {
2364 						pbeam_offset_dir[j] += f[j] * thirdp_pbeam_offset[1];
2365 						pbeam_offset_dir[j] += r[j] * thirdp_pbeam_offset[0] * newhandmult;
2366 						pbeam_offset_dir[j] += u[j] * (-thirdp_pbeam_offset[2]);
2367 					}
2368 					for (j = 0; j < 3; j++)
2369 						b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j]
2370 						    + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j])
2371 						    + pbeam_offset_dir[j];
2372 					VectorMA(b->start, (newhandmult * b->offset[0]), r, org);
2373 					VectorMA(org, b->offset[1], f, org);
2374 					VectorMA(org, b->offset[2], u, org);
2375 				} else {
2376 					for (j=0 ; j<3 ; j++) {
2377 						b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
2378 							+ cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
2379 					}
2380 					VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
2381 					VectorMA (     org, b->offset[1], cl.v_forward, org);
2382 					VectorMA (     org, b->offset[2], cl.v_up, org);
2383 					if ((hand) && (hand->value == 2)) {
2384 						VectorMA (org, -1, cl.v_up, org);
2385 					}
2386 					// FIXME - take these out when final
2387 					VectorCopy (cl.v_right, r);
2388 					VectorCopy (cl.v_forward, f);
2389 					VectorCopy (cl.v_up, u);
2390 				}
2391 
2392 			}
2393 			else
2394 				VectorCopy (b->start, org);
2395 		}
2396 		else
2397 		{
2398 			// if coming from the player, update the start position
2399 			if (firstperson)	// entity 0 is the world
2400 			{
2401 				VectorCopy (cl.refdef.vieworg, b->start);
2402 				b->start[2] -= 22;	// adjust for view height
2403 			}
2404 			VectorAdd (b->start, b->offset, org);
2405 		}
2406 
2407 		// calculate pitch and yaw
2408 		VectorSubtract (b->end, org, dist);
2409 
2410 //PMM
2411 		if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (firstperson || chasecam))
2412 		{
2413 			vec_t len;
2414 
2415 			len = VectorLength (dist);
2416 			VectorScale (f, len, dist);
2417 			if (chasecam)
2418 				VectorMA(dist, (newhandmult * b->offset[0]), r, dist);
2419 			else
2420 				VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
2421 			VectorMA (dist, b->offset[1], f, dist);
2422 			VectorMA (dist, b->offset[2], u, dist);
2423 			if (chasecam) {
2424 				VectorMA(dist, -(newhandmult * thirdp_pbeam_offset[0]), r, dist);
2425 				VectorMA(dist, thirdp_pbeam_offset[1], f, dist);
2426 				VectorMA(dist, thirdp_pbeam_offset[2], u, dist);
2427 			}
2428 			if ((hand) && (hand->value == 2) && !chasecam) {
2429 				VectorMA (org, -1, cl.v_up, org);
2430 			}
2431 		}
2432 //PMM
2433 
2434 		if (dist[1] == 0 && dist[0] == 0)
2435 		{
2436 			yaw = 0;
2437 			if (dist[2] > 0)
2438 				pitch = 90;
2439 			else
2440 				pitch = 270;
2441 		}
2442 		else
2443 		{
2444 	// PMM - fixed to correct for pitch of 0
2445 			if (dist[0])
2446 				yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
2447 			else if (dist[1] > 0)
2448 				yaw = 90;
2449 			else
2450 				yaw = 270;
2451 			if (yaw < 0)
2452 				yaw += 360;
2453 
2454 			forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
2455 			pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
2456 			if (pitch < 0)
2457 				pitch += 360.0;
2458 		}
2459 
2460 		if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam)) {
2461 			if (!firstperson) {
2462 				framenum = 2;
2463 				ent.angles[0] = -pitch;
2464 				ent.angles[1] = yaw + 180.0;
2465 				ent.angles[2] = 0;
2466 
2467 				if (!chasecam) {
2468 					AngleVectors(ent.angles, f, r, u);
2469 
2470 					// if it's a non-origin offset, it's a player, so use the hardcoded player offset
2471 					if (!VectorCompare (b->offset, vec3_origin)) {
2472 						VectorMA (org, -(b->offset[0])+1, r, org);
2473 						VectorMA (org, -(b->offset[1]), f, org);
2474 						VectorMA (org, -(b->offset[2])-10, u, org);
2475 					}
2476 					else {
2477 						// if it's a monster, do the particle effect
2478 						CL_MonsterPlasma_Shell(b->start);
2479 					}
2480 				}
2481 			}
2482 			else {
2483 				framenum = 1;
2484 			}
2485 		}
2486 
2487 		// if it's the heatbeam, draw the particle effect
2488 		if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (firstperson || chasecam))) {
2489 			CL_Heatbeam (org, dist);
2490 		}
2491 
2492 		// add new entities for the beams
2493 		d = VectorNormalize(dist);
2494 
2495 		memset (&ent, 0, sizeof(ent));
2496 		if (b->model == cl_mod_heatbeam) {
2497 			model_length = 32.0;
2498 		}
2499 		else if (b->model == cl_mod_lightning) {
2500 			model_length = 35.0;
2501 			d-= 20.0;  // correction so it doesn't end in middle of tesla
2502 		}
2503 		else {
2504 			model_length = 30.0;
2505 		}
2506 		steps = ceil(d/model_length);
2507 		len = (d-model_length)/(steps-1);
2508 
2509 		// PMM - special case for lightning model .. if the real length is shorter than the model,
2510 		// flip it around & draw it from the end to the start.  This prevents the model from going
2511 		// through the tesla mine (instead it goes through the target)
2512 		if ((b->model == cl_mod_lightning) && (d <= model_length))
2513 		{
2514 			VectorCopy (b->end, ent.origin);
2515 			// offset to push beam outside of tesla model (negative because dist is from end to start
2516 			// for this beam)
2517 			ent.model = b->model;
2518 			ent.flags = RF_FULLBRIGHT|RF_NOSHADOW;
2519 			ent.angles[0] = pitch;
2520 			ent.angles[1] = yaw;
2521 			ent.angles[2] = rand()%360;
2522 			V_AddEntity (&ent);
2523 			return;
2524 		}
2525 		while (d > 0)
2526 		{
2527 			VectorCopy (org, ent.origin);
2528 			ent.model = b->model;
2529 			if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
2530 			{
2531 				ent.angles[0] = -pitch;
2532 				ent.angles[1] = yaw + 180.0;
2533 				ent.angles[2] = (cl.stime) % 360;
2534 				ent.frame = framenum;
2535 			}
2536 			else if (b->model == cl_mod_lightning)
2537 			{
2538 				ent.flags = RF_FULLBRIGHT;
2539 				ent.angles[0] = -pitch;
2540 				ent.angles[1] = yaw + 180.0;
2541 				ent.angles[2] = rand()%360;
2542 			}
2543 			else
2544 			{
2545 				ent.angles[0] = pitch;
2546 				ent.angles[1] = yaw;
2547 				ent.angles[2] = rand()%360;
2548 			}
2549 			ent.flags |= RF_NOSHADOW;
2550 
2551 			V_AddEntity (&ent);
2552 
2553 			for (j=0 ; j<3 ; j++)
2554 				org[j] += dist[j]*len;
2555 			d -= model_length;
2556 		}
2557 	}
2558 }
2559 
2560 /*
2561 =================
2562 CL_AddExplosions
2563 =================
2564 */
CL_AddExplosions(void)2565 void CL_AddExplosions (void)
2566 {
2567 	entity_t	*ent;
2568 	explosion_t	*ex, *next, *hnode;
2569 	float		frac;
2570 	int			f;
2571 
2572 	memset (&ent, 0, sizeof(ent));
2573 
2574 	hnode = &cl_explosions_headnode;
2575 	for (ex = hnode->next; ex != hnode; ex = next)
2576 	{
2577 		next = ex->next;
2578 		ent = &ex->ent;
2579 
2580 		frac = (cl.stime - ex->start)/100.0;
2581 		f = floor(frac);
2582 
2583 		switch (ex->type)
2584 		{
2585 		case ex_mflash:
2586 			if (f >= ex->frames-1)
2587 				ex->type = ex_free;
2588 			break;
2589 		case ex_misc:
2590 			if (f >= ex->frames-1)
2591 			{
2592 				ex->type = ex_free;
2593 				break;
2594 			}
2595 			ent->alpha = 1.0 - frac/(ex->frames-1);
2596 			break;
2597 		case ex_flash:
2598 			if (f >= 1)
2599 			{
2600 				ex->type = ex_free;
2601 				break;
2602 			}
2603 			ent->alpha = 1.0;
2604 			break;
2605 		case ex_poly:
2606 			if (f >= ex->frames-1)
2607 			{
2608 				ex->type = ex_free;
2609 				break;
2610 			}
2611 
2612 			ent->alpha = (16.0 - (float)f)/16.0;
2613 
2614 			if (f < 10)
2615 			{
2616 				ent->skinnum = (f>>1);
2617 				if (ent->skinnum < 0)
2618 					ent->skinnum = 0;
2619 			}
2620 			else
2621 			{
2622 				ent->flags |= RF_TRANSLUCENT|RF_NOSHADOW;
2623 				if (f < 13)
2624 					ent->skinnum = 5;
2625 				else
2626 					ent->skinnum = 6;
2627 			}
2628 			break;
2629 		case ex_poly2:
2630 			if (f >= ex->frames-1)
2631 			{
2632 				ex->type = ex_free;
2633 				break;
2634 			}
2635 
2636 			ent->alpha = (5.0 - (float)f)/5.0;
2637 			ent->skinnum = 0;
2638 			ent->flags |= RF_TRANSLUCENT|RF_NOSHADOW;
2639 			break;
2640 		default:
2641 			break;
2642 		}
2643 
2644 		if (ex->type == ex_free)
2645 		{
2646 			CL_FreeExplosion (ex);
2647 			continue;
2648 		}
2649 
2650 		if (ex->light)
2651 		{
2652 			V_AddLight (ent->origin, ex->light*ent->alpha,
2653 				ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
2654 		}
2655 
2656 		VectorCopy (ent->origin, ent->oldorigin);
2657 
2658 		if (f < 0)
2659 			f = 0;
2660 		ent->frame = ex->baseframe + f + 1;
2661 		ent->oldframe = ex->baseframe + f;
2662 		ent->backlerp = 1.0 - cl.lerpfrac;
2663 
2664 		V_AddEntity (ent);
2665 	}
2666 }
2667 
2668 
2669 /*
2670 =================
2671 CL_AddLasers
2672 =================
2673 */
CL_AddLasers(void)2674 void CL_AddLasers (void)
2675 {
2676 	laser_t		*l;
2677 	int			i;
2678 
2679 	for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
2680 	{
2681 		if (l->endtime >= cl.stime)
2682 			V_AddEntity (&l->ent);
2683 	}
2684 }
2685 
2686 /* PMM - CL_Sustains */
CL_ProcessSustain(void)2687 void CL_ProcessSustain (void)
2688 {
2689 	cl_sustain_t	*s;
2690 	int				i;
2691 
2692 	for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
2693 	{
2694 		if (s->id) {
2695 			if ((s->endtime >= cl.stime) && (cl.stime >= s->nextthink))
2696 			{
2697 //				Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
2698 				s->think (s);
2699 			}
2700 			else if (s->endtime < cl.stime)
2701 				s->id = 0;
2702 		}
2703 	}
2704 }
2705 
2706 /*
2707 =================
2708 CL_AddTEnts
2709 =================
2710 */
CL_AddTEnts(void)2711 void CL_AddTEnts (void)
2712 {
2713 	CL_AddBeams ();
2714 	// PMM - draw plasma beams
2715 	CL_AddPlayerBeams ();
2716 	CL_AddExplosions ();
2717 	CL_AddLasers ();
2718 	// PMM - set up sustain
2719 	CL_ProcessSustain();
2720 }
2721