Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

cl_tent.c (40898B)


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