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_ents.c -- entity parsing and management
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "client.h"
27 
28 clentity_t *active_clentities, *free_clentities;
29 clentity_t clentities[MAX_CLENTITIES];
30 
31 /*
32 =========================================================================
33 
34 FRAME PARSING
35 
36 =========================================================================
37 */
38 
39 /*
40 =================
41 CL_ParseEntityBits
42 
43 Returns the entity number and the header bits
44 =================
45 */
46 int	bitcounts[32];	/// just for protocol profiling
CL_ParseEntityBits(unsigned * bits)47 int CL_ParseEntityBits (unsigned *bits)
48 {
49 	unsigned	b, total;
50 	int			i;
51 	int			number;
52 
53 	total = MSG_ReadByte (&net_message);
54 	if (total & U_MOREBITS1)
55 	{
56 		b = MSG_ReadByte (&net_message);
57 		total |= b<<8;
58 	}
59 	if (total & U_MOREBITS2)
60 	{
61 		b = MSG_ReadByte (&net_message);
62 		total |= b<<16;
63 	}
64 	if (total & U_MOREBITS3)
65 	{
66 		b = MSG_ReadByte (&net_message);
67 		total |= b<<24;
68 	}
69 
70 	// count the bits for net profiling
71 	for (i=0 ; i<32 ; i++)
72 		if (total&(1<<i))
73 			bitcounts[i]++;
74 
75 	if (total & U_NUMBER16)
76 		number = MSG_ReadShort (&net_message);
77 	else
78 		number = MSG_ReadByte (&net_message);
79 
80 	*bits = total;
81 
82 	return number;
83 }
84 
85 /*
86 ==================
87 CL_ParseDelta
88 
89 Can go from either a baseline or a previous packet_entity
90 ==================
91 */
CL_ParseDelta(entity_state_t * from,entity_state_t * to,int number,int bits)92 void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
93 {
94 	// set everything to the state we are delta'ing from
95 	*to = *from;
96 
97 	VectorCopy (from->origin, to->old_origin);
98 	to->number = number;
99 
100 	if (bits & U_MODEL)
101 		to->modelindex = MSG_ReadByte (&net_message);
102 	if (bits & U_MODEL2)
103 		to->modelindex2 = MSG_ReadByte (&net_message);
104 	if (bits & U_MODEL3)
105 		to->modelindex3 = MSG_ReadByte (&net_message);
106 	if (bits & U_MODEL4)
107 		to->modelindex4 = MSG_ReadByte (&net_message);
108 
109 	if (bits & U_FRAME8)
110 		to->frame = MSG_ReadByte (&net_message);
111 	if (bits & U_FRAME16)
112 		to->frame = MSG_ReadShort (&net_message);
113 
114 	if ((bits & U_SKIN8) && (bits & U_SKIN16))		//used for laser colors
115 		to->skinnum = MSG_ReadLong(&net_message);
116 	else if (bits & U_SKIN8)
117 		to->skinnum = MSG_ReadByte(&net_message);
118 	else if (bits & U_SKIN16)
119 		to->skinnum = MSG_ReadShort(&net_message);
120 
121 	if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
122 		to->effects = MSG_ReadLong(&net_message);
123 	else if (bits & U_EFFECTS8)
124 		to->effects = MSG_ReadByte(&net_message);
125 	else if (bits & U_EFFECTS16)
126 		to->effects = MSG_ReadShort(&net_message);
127 
128 	if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
129 		to->renderfx = MSG_ReadLong(&net_message);
130 	else if (bits & U_RENDERFX8)
131 		to->renderfx = MSG_ReadByte(&net_message);
132 	else if (bits & U_RENDERFX16)
133 		to->renderfx = MSG_ReadShort(&net_message);
134 
135 	if (bits & U_ORIGIN1)
136 		to->origin[0] = MSG_ReadCoord (&net_message);
137 	if (bits & U_ORIGIN2)
138 		to->origin[1] = MSG_ReadCoord (&net_message);
139 	if (bits & U_ORIGIN3)
140 		to->origin[2] = MSG_ReadCoord (&net_message);
141 
142 	if (bits & U_ANGLE1)
143 		to->angles[0] = MSG_ReadAngle(&net_message);
144 	if (bits & U_ANGLE2)
145 		to->angles[1] = MSG_ReadAngle(&net_message);
146 	if (bits & U_ANGLE3)
147 		to->angles[2] = MSG_ReadAngle(&net_message);
148 
149 	if (bits & U_OLDORIGIN)
150 		MSG_ReadPos (&net_message, to->old_origin);
151 
152 	if (bits & U_SOUND)
153 		to->sound = MSG_ReadByte (&net_message);
154 
155 	if (bits & U_EVENT)
156 		to->event = MSG_ReadByte (&net_message);
157 	else
158 		to->event = 0;
159 
160 	if (bits & U_SOLID)
161 		to->solid = MSG_ReadShort (&net_message);
162 }
163 
164 /*
165 ==================
166 CL_DeltaEntity
167 
168 Parses deltas from the given base and adds the resulting entity
169 to the current frame
170 ==================
171 */
CL_DeltaEntity(frame_t * frame,int newnum,entity_state_t * old,int bits)172 void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
173 {
174 	centity_t	*ent;
175 	entity_state_t	*state;
176 
177 	ent = &cl_entities[newnum];
178 
179 	state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
180 	cl.parse_entities++;
181 	frame->num_entities++;
182 
183 	CL_ParseDelta (old, state, newnum, bits);
184 
185 	// some data changes will force no lerping
186 	if (state->modelindex != ent->current.modelindex
187 		|| state->modelindex2 != ent->current.modelindex2
188 		|| state->modelindex3 != ent->current.modelindex3
189 		|| state->modelindex4 != ent->current.modelindex4
190 		|| abs(state->origin[0] - ent->current.origin[0]) > 512
191 		|| abs(state->origin[1] - ent->current.origin[1]) > 512
192 		|| abs(state->origin[2] - ent->current.origin[2]) > 512
193 		|| state->event == EV_PLAYER_TELEPORT
194 		|| state->event == EV_OTHER_TELEPORT
195 		)
196 	{
197 		ent->serverframe = -99;
198 	}
199 
200 	if (ent->serverframe != cl.frame.serverframe - 1)
201 	{	// wasn't in last update, so initialize some things
202 		ent->trailcount = 1024;		// for diminishing rocket / grenade trails
203 		ent->pr = NULL;             // for chained particle trails
204 		// duplicate the current state so lerping doesn't hurt anything
205 		ent->prev = *state;
206 		if (state->event == EV_OTHER_TELEPORT)
207 		{
208 			VectorCopy (state->origin, ent->prev.origin);
209 			VectorCopy (state->origin, ent->lerp_origin);
210 		}
211 		else
212 		{
213 			VectorCopy (state->old_origin, ent->prev.origin);
214 			VectorCopy (state->old_origin, ent->lerp_origin);
215 		}
216 	}
217 	else
218 	{	// shuffle the last state to previous
219 		ent->prev = ent->current;
220 	}
221 
222 	ent->serverframe = cl.frame.serverframe;
223 	ent->current = *state;
224 }
225 
226 /*
227 ==================
228 CL_ParsePacketEntities
229 
230 An svc_packetentities has just been parsed, deal with the
231 rest of the data stream.
232 ==================
233 */
CL_ParsePacketEntities(frame_t * oldframe,frame_t * newframe)234 void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
235 {
236 	int			newnum;
237 	int			bits;
238 	entity_state_t	*oldstate = NULL;
239 	int			oldindex, oldnum;
240 
241 	newframe->parse_entities = cl.parse_entities;
242 	newframe->num_entities = 0;
243 
244 	// delta from the entities present in oldframe
245 	oldindex = 0;
246 	if (!oldframe)
247 		oldnum = 99999;
248 	else
249 	{
250 		if (oldindex >= oldframe->num_entities)
251 			oldnum = 99999;
252 		else
253 		{
254 			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
255 			oldnum = oldstate->number;
256 		}
257 	}
258 
259 	while (1)
260 	{
261 		newnum = CL_ParseEntityBits ( (unsigned *)&bits );
262 		if (newnum >= MAX_EDICTS)
263 			Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
264 
265 		if (net_message.readcount > net_message.cursize)
266 			Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
267 
268 		if (!newnum)
269 			break;
270 
271 		while (oldnum < newnum)
272 		{	// one or more entities from the old packet are unchanged
273 			if (cl_shownet->value == 3)
274 				Com_Printf ("   unchanged: %i\n", oldnum);
275 			CL_DeltaEntity (newframe, oldnum, oldstate, 0);
276 
277 			oldindex++;
278 
279 			if (oldindex >= oldframe->num_entities)
280 				oldnum = 99999;
281 			else
282 			{
283 				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
284 				oldnum = oldstate->number;
285 			}
286 		}
287 
288 		if (bits & U_REMOVE)
289 		{	// the entity present in oldframe is not in the current frame
290 			if (cl_shownet->value == 3)
291 				Com_Printf ("   remove: %i\n", newnum);
292 			if (oldnum != newnum)
293 				Com_Printf ("U_REMOVE: oldnum != newnum\n");
294 
295 			oldindex++;
296 
297 			if (oldindex >= oldframe->num_entities)
298 				oldnum = 99999;
299 			else
300 			{
301 				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
302 				oldnum = oldstate->number;
303 			}
304 			continue;
305 		}
306 
307 		if (oldnum == newnum)
308 		{	// delta from previous state
309 			if (cl_shownet->value == 3)
310 				Com_Printf ("   delta: %i\n", newnum);
311 			CL_DeltaEntity (newframe, newnum, oldstate, bits);
312 
313 			oldindex++;
314 
315 			if (oldindex >= oldframe->num_entities)
316 				oldnum = 99999;
317 			else
318 			{
319 				oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
320 				oldnum = oldstate->number;
321 			}
322 			continue;
323 		}
324 
325 		if (oldnum > newnum)
326 		{	// delta from baseline
327 			if (cl_shownet->value == 3)
328 				Com_Printf ("   baseline: %i\n", newnum);
329 			CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
330 			continue;
331 		}
332 
333 	}
334 
335 	// any remaining entities in the old frame are copied over
336 	while (oldnum != 99999)
337 	{	// one or more entities from the old packet are unchanged
338 		if (cl_shownet->value == 3)
339 			Com_Printf ("   unchanged: %i\n", oldnum);
340 		CL_DeltaEntity (newframe, oldnum, oldstate, 0);
341 
342 		oldindex++;
343 
344 		if (oldindex >= oldframe->num_entities)
345 			oldnum = 99999;
346 		else
347 		{
348 			oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
349 			oldnum = oldstate->number;
350 		}
351 	}
352 }
353 
354 
355 
356 /*
357 ===================
358 CL_ParsePlayerstate
359 ===================
360 */
CL_ParsePlayerstate(frame_t * oldframe,frame_t * newframe)361 void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
362 {
363 	int			flags;
364 	player_state_t	*state;
365 	int			i;
366 	int			statbits;
367 
368 	state = &newframe->playerstate;
369 
370 	// clear to old value before delta parsing
371 	if (oldframe)
372 		*state = oldframe->playerstate;
373 	else
374 		memset (state, 0, sizeof(*state));
375 
376 	flags = MSG_ReadShort (&net_message);
377 
378 	//
379 	// parse the pmove_state_t
380 	//
381 	if (flags & PS_M_TYPE)
382 		state->pmove.pm_type = MSG_ReadByte (&net_message);
383 
384 	if (flags & PS_M_ORIGIN)
385 	{
386 		state->pmove.origin[0] = MSG_ReadSizeInt (&net_message, coord_bytes);
387 		state->pmove.origin[1] = MSG_ReadSizeInt (&net_message, coord_bytes);
388 		state->pmove.origin[2] = MSG_ReadSizeInt (&net_message, coord_bytes);
389 	}
390 
391 	if (flags & PS_M_VELOCITY)
392 	{
393 		state->pmove.velocity[0] = MSG_ReadShort (&net_message);
394 		state->pmove.velocity[1] = MSG_ReadShort (&net_message);
395 		state->pmove.velocity[2] = MSG_ReadShort (&net_message);
396 	}
397 
398 	if (flags & PS_M_TIME)
399 		state->pmove.pm_time = MSG_ReadByte (&net_message);
400 
401 	if (flags & PS_M_FLAGS)
402 		state->pmove.pm_flags = MSG_ReadByte (&net_message);
403 
404 	if (flags & PS_M_GRAVITY)
405 		state->pmove.gravity = MSG_ReadShort (&net_message);
406 
407 	if (flags & PS_M_DELTA_ANGLES)
408 	{
409 		state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
410 		state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
411 		state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
412 	}
413 
414 	if (cl.attractloop)
415 		state->pmove.pm_type = PM_FREEZE;		// demo playback
416 
417 	//
418 	// parse the rest of the player_state_t
419 	//
420 	if (flags & PS_VIEWOFFSET)
421 	{
422 		state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
423 		state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
424 		state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
425 	}
426 
427 	if (flags & PS_VIEWANGLES)
428 	{
429 		state->viewangles[0] = MSG_ReadAngle16 (&net_message);
430 		state->viewangles[1] = MSG_ReadAngle16 (&net_message);
431 		state->viewangles[2] = MSG_ReadAngle16 (&net_message);
432 	}
433 
434 	if (flags & PS_KICKANGLES)
435 	{
436 		state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
437 		state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
438 		state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
439 	}
440 
441 	if (flags & PS_WEAPONINDEX)
442 	{
443 		state->gunindex = MSG_ReadByte (&net_message);
444 	}
445 
446 	if (flags & PS_WEAPONFRAME)
447 	{
448 		state->gunframe = MSG_ReadByte (&net_message);
449 		state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
450 		state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
451 		state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
452 		state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
453 		state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
454 		state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
455 	}
456 
457 	if (flags & PS_BLEND)
458 	{
459 		state->blend[0] = MSG_ReadByte (&net_message)/255.0;
460 		state->blend[1] = MSG_ReadByte (&net_message)/255.0;
461 		state->blend[2] = MSG_ReadByte (&net_message)/255.0;
462 		state->blend[3] = MSG_ReadByte (&net_message)/255.0;
463 	}
464 
465 	if (flags & PS_FOV)
466 		state->fov = MSG_ReadByte (&net_message);
467 
468 	if (flags & PS_RDFLAGS)
469 		state->rdflags = MSG_ReadByte (&net_message);
470 
471 	// parse stats
472 	statbits = MSG_ReadLong (&net_message);
473 	for (i=0 ; i<MAX_STATS ; i++)
474 		if (statbits & (1<<i) )
475 			state->stats[i] = MSG_ReadShort(&net_message);
476 }
477 
478 
479 /*
480 ==================
481 CL_FireEntityEvents
482 
483 ==================
484 */
CL_FireEntityEvents(frame_t * frame)485 void CL_FireEntityEvents (frame_t *frame)
486 {
487 	entity_state_t		*s1;
488 	int					pnum, num;
489 
490 	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
491 	{
492 		num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
493 		s1 = &cl_parse_entities[num];
494 		if (s1->event)
495 			CL_EntityEvent (s1);
496 
497 		// EF_TELEPORTER acts like an event, but is not cleared each frame
498 		if (s1->effects & EF_TELEPORTER)
499 			CL_BigTeleportParticles(s1->origin);
500 	}
501 }
502 
503 
504 /*
505 ================
506 CL_ParseFrame
507 ================
508 */
CL_ParseFrame(void)509 void CL_ParseFrame (void)
510 {
511 	int			cmd;
512 	int			len;
513 	frame_t		*old;
514 	byte		new_areabits[MAX_MAP_AREAS/8];
515 
516 	//HACK: reduce the number of areabit changes detected
517 	memcpy (new_areabits, cl.frame.areabits, MAX_MAP_AREAS/8);
518 	memset (&cl.frame, 0, sizeof(cl.frame));
519 	memcpy (cl.frame.areabits, new_areabits, MAX_MAP_AREAS/8);
520 
521 	cl.frame.serverframe = MSG_ReadLong (&net_message);
522 	cl.frame.deltaframe = MSG_ReadLong (&net_message);
523 	cl.frame.servertime = cl.frame.serverframe*100;
524 
525 	// BIG HACK to let old demos continue to work
526 	if (cls.serverProtocol != 26)
527 		cl.surpressCount = MSG_ReadByte (&net_message);
528 
529 	if (cl_shownet->value == 3)
530 		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.serverframe,
531 		cl.frame.deltaframe);
532 
533 	// If the frame is delta compressed from data that we
534 	// no longer have available, we must suck up the rest of
535 	// the frame, but not use it, then ask for a non-compressed
536 	// message
537 	if (cl.frame.deltaframe <= 0)
538 	{
539 		cl.frame.valid = true;		// uncompressed frame
540 		old = NULL;
541 		cls.demowaiting = false;	// we can start recording now
542 	}
543 	else
544 	{
545 		old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
546 		if (!old->valid)
547 		{	// should never happen
548 			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
549 		}
550 		if (old->serverframe != cl.frame.deltaframe)
551 		{	// The frame that the server did the delta from
552 			// is too old, so we can't reconstruct it properly.
553 			Com_Printf ("Delta frame too old.\n");
554 		}
555 		else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
556 		{
557 			Com_Printf ("Delta parse_entities too old.\n");
558 		}
559 		else
560 			cl.frame.valid = true;	// valid delta parse
561 	}
562 
563 	// clamp time
564 	if (cl.time > cl.frame.servertime)
565 		cl.time = cl.frame.servertime;
566 	else if (cl.time < cl.frame.servertime - 100)
567 		cl.time = cl.frame.servertime - 100;
568 
569 	// read areabits
570 	len = MSG_ReadByte (&net_message);
571 	MSG_ReadData (&net_message, &new_areabits, len);
572 	if (memcmp (cl.frame.areabits, new_areabits, len))
573 	{
574 		memcpy (cl.frame.areabits, new_areabits, len);
575 		cl.refdef.areabits_changed = true;
576 	}
577 
578 	// read playerinfo
579 	cmd = MSG_ReadByte (&net_message);
580 	SHOWNET(svc_strings[cmd]);
581 	if (cmd != svc_playerinfo)
582 		Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
583 	CL_ParsePlayerstate (old, &cl.frame);
584 
585 	// read packet entities
586 	cmd = MSG_ReadByte (&net_message);
587 	SHOWNET(svc_strings[cmd]);
588 	if (cmd != svc_packetentities)
589 		Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
590 	CL_ParsePacketEntities (old, &cl.frame);
591 
592 	// save the frame off in the backup array for later delta comparisons
593 	cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
594 
595 	if (cl.frame.valid)
596 	{
597 		// getting a valid frame message ends the connection process
598 		if (cls.state != ca_active)
599 		{
600 			cls.state = ca_active;
601 			cl.force_refdef = true;
602 			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
603 			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
604 			cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
605 			VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
606 			if (cls.disable_servercount != cl.servercount
607 				&& cl.refresh_prepped)
608 				SCR_EndLoadingPlaque ();	// get rid of loading plaque
609 		}
610 		cl.sound_prepped = true;	// can start mixing ambient sounds
611 
612 		// fire entity events
613 		CL_FireEntityEvents (&cl.frame);
614 		CL_CheckPredictionError ();
615 	}
616 }
617 
618 /*
619 ==========================================================================
620 
621 INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
622 
623 ==========================================================================
624 */
625 
626 /*
627 ===============
628 CL_AddPacketEntities
629 
630 ===============
631 */
632 struct model_s
633 {
634 	char		name[MAX_QPATH];
635 };
636 
CL_AddPacketEntities(frame_t * frame)637 void CL_AddPacketEntities (frame_t *frame)
638 {
639 	entity_t			ent;
640 	entity_state_t		*s1;
641 	float				autorotate;
642 	float				bob, bob_scale;
643 	int					i;
644 	int					pnum;
645 	centity_t			*cent;
646 	int					autoanim;
647 	clientinfo_t		*ci;
648 	unsigned int		effects, renderfx;
649 	qboolean			playermodel;
650 
651 	// bonus items rotate at a fixed rate
652 	autorotate = anglemod(cl.time/10);
653 
654 	// brush models can auto animate their frames
655 	autoanim = 2*cl.time/1000;
656 
657 	memset (&ent, 0, sizeof(ent));
658 
659 	for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
660 	{
661 		s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
662 
663 		cent = &cl_entities[s1->number];
664 
665 		ent.number = s1->number;
666 
667 		playermodel = false;
668 
669 		effects = s1->effects;
670 		renderfx = s1->renderfx;
671 
672 			// set frame
673 		if (effects & EF_ANIM01)
674 			ent.frame = autoanim & 1;
675 		else if (effects & EF_ANIM23)
676 			ent.frame = 2 + (autoanim & 1);
677 		else if (effects & EF_ANIM_ALL)
678 			ent.frame = autoanim;
679 		else if (effects & EF_ANIM_ALLFAST)
680 			ent.frame = cl.time / 100;
681 		else
682 			ent.frame = s1->frame;
683 
684 		// quad and pent can do different things on client
685 		if (effects & EF_PENT)
686 		{
687 			effects &= ~EF_PENT;
688 			effects |= EF_COLOR_SHELL;
689 			renderfx |= RF_SHELL_RED;
690 		}
691 
692 		if (effects & EF_QUAD)
693 		{
694 			effects &= ~EF_QUAD;
695 			effects |= EF_COLOR_SHELL;
696 			renderfx |= RF_SHELL_BLUE;
697 		}
698 
699 		ent.oldframe = cent->prev.frame;
700 		ent.backlerp = 1.0 - cl.lerpfrac;
701 
702 		//animation timestamps are set here
703 		if(cent->prevframe != s1->frame) {
704 			cent->prevframe = s1->frame;
705 			cent->frametime = Sys_Milliseconds();
706 		}
707 		ent.prevframe = cent->prevframe;
708 		ent.frametime = cent->frametime;
709 
710 		// create a new entity
711 
712 		ent.lod1 = NULL;
713 		ent.lod2 = NULL;
714 		ent.team = 0;
715 
716 		// set skin
717 		if (s1->modelindex == 255)
718 		{	// use custom player skin
719 			ent.skinnum = 0;
720 			ci = &cl.clientinfo[s1->skinnum & 0xff];
721 			ent.skin = ci->skin;
722 			ent.model = ci->model;
723 
724 			ent.lod1 = ci->lod1;
725 
726 			ent.lod2 = ci->lod2;
727 
728 			if (!ent.skin || !ent.model)
729 			{
730 				ent.skin = cl.baseclientinfo.skin;
731 				ent.model = cl.baseclientinfo.model;
732 			}
733 			playermodel = true;
734 
735 			strcpy(ent.name, ci->name);
736 
737 		}
738 		else
739 		{
740 			ent.skinnum = s1->skinnum;
741 			ent.skin = NULL;
742 			ent.model = cl.model_draw[s1->modelindex];
743 		}
744 
745 		if (renderfx & (RF_FRAMELERP))
746 		{	// step origin discretely, because the frames
747 			// do the animation properly
748 			VectorCopy (cent->current.origin, ent.origin);
749 			VectorCopy (cent->current.old_origin, ent.oldorigin);
750 		}
751 		else if (s1->number == cl.playernum+1)
752 		{
753 			for (i=0; i<3; i++) {
754 				ent.origin[i] = ent.oldorigin[i] = cent->current.origin[i] + cl.lerpfrac *
755 					(cent->current.origin[i] - cent->prev.origin[i]);
756 			}
757 		}
758 		else
759 		{	// interpolate origin
760 			for (i=0 ; i<3 ; i++)
761 			{
762 				ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
763 					(cent->current.origin[i] - cent->prev.origin[i]);
764 			}
765 		}
766 
767 		// calculate angles
768 		if (effects & EF_ROTATE)
769 		{	// some bonus items auto-rotate
770 			ent.angles[0] = 0;
771 			ent.angles[1] = autorotate;
772 			ent.angles[2] = 0;
773 			// bobbing items
774 			bob_scale = (0.005f + s1->number * 0.00001f) * 0.5;
775 			bob = 5 + cos( (cl.time + 1000) * bob_scale ) * 5;
776 			ent.oldorigin[2] += bob;
777 			ent.origin[2] += bob;
778 
779 			ent.bob = bob;
780 
781 			renderfx |= RF_BOBBING;
782 		}
783 		else
784 		{	// interpolate angles
785 			float	a1, a2;
786 
787 			for (i=0 ; i<3 ; i++)
788 			{
789 				a1 = cent->current.angles[i];
790 				a2 = cent->prev.angles[i];
791 				ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
792 			}
793 		}
794 
795 		// render effects (fullbright, translucent, etc)
796 		if ((effects & EF_COLOR_SHELL))
797 			ent.flags = 0;	// renderfx go on color shell entity
798 		else
799 			ent.flags = renderfx;
800 
801 		if (s1->number == cl.playernum+1)
802 		{
803 			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
804 			// fixed player origin - fixes the "jittery" player shadows too
805 			if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
806 			{
807 				VectorCopy (cl.predicted_origin, ent.origin);
808 				VectorCopy (cl.predicted_origin, ent.oldorigin);
809 			}
810 
811 		}
812 
813 		// Sigh, this is the reason for the RF_NODRAW workaround.
814 #if 1 // TODO: replace this with an IFDEF for non Alien Arena CRX games
815 		// if set to invisible, skip
816 		if (!s1->modelindex)
817 			continue;
818 #endif
819 
820 		if (effects & EF_PLASMA)
821 		{
822 			ent.flags |= RF_TRANSLUCENT;
823 			ent.alpha = 0.6;
824 		}
825 
826 		if (effects & EF_BUBBLES)
827 		{
828 			CL_PoweredEffects (ent.origin);
829 		}
830 
831 		//cool new ctf flag effects
832 		if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/flags/flag1.md2"))
833 		{
834 			CL_FlagEffects(ent.origin, 0);
835 			ent.team = 1;
836 		}
837 		else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/flags/flag2.md2"))
838 		{
839 			CL_FlagEffects(ent.origin, 1);
840 			ent.team = 2;
841 		}
842 
843 		if (s1->modelindex != 0 && !(renderfx & RF_NODRAW))
844 		{
845 			// add to refresh list
846 			V_AddEntity (&ent);
847 
848 			// color shells generate a seperate entity for the main model
849 			if ((effects & EF_COLOR_SHELL) && !(s1->number == cl.playernum+1))
850 			{
851 
852 				ent.flags = renderfx | RF_TRANSLUCENT;
853 				ent.alpha = 0.30;
854 				V_AddViewEntity (&ent);
855 			}
856 		}
857 
858 		ent.skin = NULL;		// never use a custom skin on others
859 		ent.skinnum = 0;
860 		ent.flags = 0;
861 		ent.alpha = 0;
862 		ent.lod1 = NULL;		// only player models get lods
863 		ent.lod2 = NULL;
864 		ent.team = 0;
865 
866 		ci = &cl.clientinfo[s1->skinnum & 0xff];
867 
868 		if (s1->modelindex != 0 && !(renderfx & RF_NODRAW))
869 		{
870 			//give health an "aura"
871 			if(cl_healthaura->value && !cl_simpleitems->value)
872 			{
873 				if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/small/tris.md2"))
874 					CL_SmallHealthParticles(ent.origin);
875 				if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/medium/tris.md2"))
876 					CL_MedHealthParticles(ent.origin);
877 				if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/large/tris.md2"))
878 					CL_LargeHealthParticles(ent.origin);
879 			}
880 
881 			if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/weapons/g_rocket/tris.md2"))
882 			{
883 				//add clear cover
884 				if (!cl_simpleitems->integer)
885 				{
886 					ent.model = R_RegisterModel("models/weapons/g_rocket/cover.md2");
887 					ent.flags |= RF_TRANSLUCENT;
888 					ent.alpha = 0.30;
889 					V_AddEntity (&ent);
890 				}
891 			}
892 			if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/weapons/g_hyperb/tris.md2"))
893 			{
894 				//add clear cover
895 				if (!cl_simpleitems->integer)
896 				{
897 					ent.model = R_RegisterModel("models/weapons/g_hyperb/cover.md2");
898 					ent.flags |= RF_TRANSLUCENT;
899 					ent.alpha = 0.30;
900 					V_AddEntity (&ent);
901 				}
902 			}
903 		}
904 
905 		if (s1->modelindex2)
906 		{
907 			if (s1->modelindex2 == 255 || (ci->helmet && playermodel))
908 			{	// custom weapon
909 
910 				i = (s1->skinnum >> 8); // 0 is default weapon model
911 				if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
912 					i = 0;
913 				ent.model = ci->weaponmodel[i];
914 				if (!ent.model)
915 				{
916 					if (i != 0)
917 						ent.model = ci->weaponmodel[0];
918 					if (!ent.model)
919 						ent.model = cl.baseclientinfo.weaponmodel[0];
920 				}
921 			}
922 			else
923 			{
924 				ent.model = cl.model_draw[s1->modelindex2];
925 			}
926 
927 			//here is where we will set the alpha for certain model parts - would like to eventually
928 			//do something a little less uh, hardcoded.
929 			if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex2)], "models/items/healing/globe/tris.md2"))
930 			{
931 				if(cl_simpleitems->value)
932 					continue;
933 				ent.alpha = 0.4;
934 				ent.flags = RF_TRANSLUCENT;
935 			}
936 			else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex2)], "models/items/quaddama/unit.md2"))
937 			{
938 				if(cl_simpleitems->value)
939 					continue;
940 				ent.alpha = 0.4;
941 				ent.flags = RF_TRANSLUCENT;
942 			}
943 
944 			if (s1->number == cl.playernum+1)
945 				ent.flags |= RF_VIEWERMODEL;
946 
947 			V_AddEntity (&ent);
948 
949 			//PGM - make sure these get reset.
950 			ent.flags = 0;
951 			ent.alpha = 0;
952 			//PGM
953 
954 		}
955 
956 		if (s1->modelindex3 || (ci->helmet && playermodel)) //index 3 is only used for clear entities now, no need for all that checking
957 		{
958 			if(ci->helmet && playermodel)
959 				ent.model = ci->helmet;
960 			else
961 				ent.model = cl.model_draw[s1->modelindex3];
962 
963 			ent.alpha = 0.4;
964 			ent.flags = RF_TRANSLUCENT;
965 
966 			if (s1->number == cl.playernum+1) {
967 				ent.flags |= RF_VIEWERMODEL;
968 			}
969 			V_AddEntity (&ent);
970 		}
971 
972 		if (s1->number == cl.playernum+1)
973 			goto end;
974 
975 		if (s1->modelindex4)
976 		{
977 			ent.flags = 0;
978 			ent.alpha = 1.0;
979 
980 			//new ctf flag effects
981 			if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex4)], "models/items/flags/flag1.md2"))
982 			{
983 				CL_FlagEffects(ent.origin, 0);
984 				ent.model = 0;
985 			}
986 			else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex4)], "models/items/flags/flag2.md2"))
987 			{
988 				CL_FlagEffects(ent.origin, 1);
989 				ent.model = 0;
990 			}
991 			else
992 			{
993 				ent.model = cl.model_draw[s1->modelindex4];
994 				V_AddEntity (&ent);
995 			}
996 		}
997 
998 		// add automatic particle trails
999 		if ( (effects&~EF_ROTATE) )
1000 		{
1001 			if (effects & EF_ROCKET)
1002 			{
1003 				CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
1004 				V_AddLight (ent.origin, 200, .4, .4, .1);
1005 			}
1006 			if (effects & EF_SHIPEXHAUST)
1007 			{
1008 				CL_ShipExhaust (cent->lerp_origin, ent.origin, cent);
1009 			}
1010 			if (effects & EF_ROCKETEXHAUST)
1011 			{
1012 				CL_RocketExhaust (cent->lerp_origin, ent.origin, cent);
1013 			}
1014 			else if (effects & EF_HYPERBLASTER)
1015 			{
1016 				V_AddLight (ent.origin, 400*crand(), 1, 0, 1);
1017 			}
1018 			else if (effects & EF_GIB)
1019 			{
1020 				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1021 			}
1022 			else if (effects & EF_GRENADE)
1023 			{
1024 				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1025 			}
1026 			else if (effects & EF_TEAM1)
1027 			{
1028 				vec3_t right;
1029 				vec3_t start;
1030 				vec3_t up;
1031 
1032 				AngleVectors (ent.angles, NULL, right, up);
1033 				VectorMA (ent.origin, 16, right, start);
1034 				VectorMA (start, 32, up, start);
1035 				CL_RedTeamLight(start);
1036 
1037 				VectorMA (ent.origin, -16, right, start);
1038 				VectorMA (start, 32, up, start);
1039 				CL_RedTeamLight(start);
1040 			}
1041 			else if (effects & EF_TEAM2)
1042 			{
1043 
1044 				vec3_t right;
1045 				vec3_t start;
1046 				vec3_t up;
1047 
1048 				AngleVectors (ent.angles, NULL, right, up);
1049 				VectorMA (ent.origin, 16, right, start);
1050 				VectorMA (start, 32, up, start);
1051 				CL_BlueTeamLight(start);
1052 
1053 				VectorMA (ent.origin, -16, right, start);
1054 				VectorMA (start, 32, up, start);
1055 				CL_BlueTeamLight(start);
1056 			}
1057 
1058 			else if (effects & EF_GREENGIB)
1059 			{
1060 				CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1061 			}
1062 
1063 			else if (effects & EF_PLASMA)
1064 			{
1065 				CL_BlasterBall (cent->lerp_origin, ent.origin);
1066 				V_AddLight (ent.origin, 200, 0, 1, 1);
1067 			}
1068 			else if (effects & EF_BLASTER)
1069 			{
1070 				CL_BlasterTrail(cent->lerp_origin, ent.origin, cent);
1071 				V_AddLight (ent.origin, 200, 0, .5, .1);
1072 			}
1073 		}
1074 end:
1075 		VectorCopy (ent.origin, cent->lerp_origin);
1076 	}
1077 }
1078 
1079 /*
1080 =======================
1081 Berserker@quake2  shell
1082 brass effect. No change
1083 =======================
1084 */
1085 
CL_BrassShells(vec3_t org,vec3_t dir,int count)1086 void CL_BrassShells(vec3_t org, vec3_t dir, int count)
1087 {
1088 	int i, j;
1089 	clentity_t *le;
1090 	float d;
1091 
1092 	if (!cl_brass->value || !count)
1093 		return;
1094 
1095 	for (i = 0; i < count; i++) {
1096 
1097 		if (!free_clentities)
1098 			return;
1099 
1100 		le = free_clentities;
1101 		free_clentities = le->next;
1102 		le->next = active_clentities;
1103 		active_clentities = le;
1104 		le->time = cl.time;
1105 		d = (192 + rand()) & 63;
1106 		VectorClear(le->accel);
1107 		VectorClear(le->vel);
1108 		le->accel[0] = le->accel[1] = 0;
1109 		le->accel[2] = -6 * PARTICLE_GRAVITY;
1110 		le->alpha = 1.0;
1111 		le->alphavel = -0.1;
1112 		le->flags = CLM_BOUNCE | CLM_FRICTION | CLM_ROTATE | CLM_NOSHADOW | CLM_BRASS;
1113 		le->model = R_RegisterModel("models/objects/brass/tris.md2");
1114 		le->ang = crand() * 360;
1115 		le->avel = crand() * 500;
1116 
1117 		for (j = 0; j < 3; j++) {
1118 			le->lastOrg[j] = le->org[j] = org[j];
1119 			le->vel[j] = crand() * 24 + d * dir[j];
1120 		}
1121 	}
1122 }
1123 
CL_GlassShards(vec3_t org,vec3_t dir,int count)1124 void CL_GlassShards(vec3_t org, vec3_t dir, int count)
1125 {
1126 	int i, j;
1127 	clentity_t *le;
1128 	float d;
1129 
1130 	if (!count)
1131 		return;
1132 
1133 	for (i = 0; i < count; i++) {
1134 
1135 		if (!free_clentities)
1136 			return;
1137 
1138 		le = free_clentities;
1139 		free_clentities = le->next;
1140 		le->next = active_clentities;
1141 		active_clentities = le;
1142 		le->time = cl.time;
1143 		d = (192 + rand()) & 13;
1144 		VectorClear(le->accel);
1145 		VectorClear(le->vel);
1146 		le->accel[0] = le->accel[1] = 0;
1147 		le->accel[2] = -3 * PARTICLE_GRAVITY;
1148 		le->alpha = 1.0;
1149 		le->alphavel = -0.01;
1150 		le->flags = CLM_BOUNCE | CLM_FRICTION | CLM_ROTATE | CLM_NOSHADOW | CLM_GLASS;
1151 		le->model = R_RegisterModel("models/objects/debris1/tris.md2");
1152 		le->ang = crand() * 360;
1153 		le->avel = crand() * 500;
1154 
1155 		for (j = 0; j < 3; j++) {
1156 			le->lastOrg[j] = le->org[j] = org[j];
1157 			le->vel[j] = crand() * 12 + d * dir[j];
1158 		}
1159 	}
1160 }
1161 
1162 /*
1163 ==============
1164 CL_AddViewWeapon
1165 ==============
1166 */
1167 
CL_AddViewWeapon(player_state_t * ps,player_state_t * ops)1168 void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
1169 {
1170 	entity_t	gun;		// view model
1171 	int			i;
1172 	qboolean	useFX = false;
1173 	vec3_t		offset_down;
1174 	vec3_t		offset_right;
1175 
1176 	memset (&gun, 0, sizeof(gun));
1177 
1178 	gun.model = cl.model_draw[ps->gunindex];
1179 
1180 	gun.lod1 = NULL;
1181 	gun.lod2 = NULL;
1182 
1183 	if (!gun.model)
1184 		return;
1185 
1186 	//if a vehicle console, we want to render as a 2D HUD now, if a player choses to
1187 	if(cl_vehicle_huds->value)
1188 	{
1189 		if(!(strcmp("vehicles/bomber/v_wep.md2", gun.model->name)))
1190 		{
1191 			vehicle_hud = 1;
1192 			return;
1193 		}
1194 		else if(!(strcmp("vehicles/strafer/v_wep.md2", gun.model->name)))
1195 		{
1196 			vehicle_hud = 2;
1197 			return;
1198 		}
1199 		else if(!(strcmp("vehicles/hover/v_wep.md2", gun.model->name)))
1200 		{
1201 			vehicle_hud = 3;
1202 			return;
1203 		}
1204 		else
1205 			vehicle_hud = 0;
1206 	}
1207 	else
1208 		vehicle_hud = 0;
1209 
1210 	// nudge gun down and right if in wide angle view
1211 	if(cl.refdef.fov_x > 90)
1212 	{
1213 		VectorScale(cl.v_up, 0.2 * (cl.refdef.fov_x - 90), offset_down);
1214 		VectorScale(cl.v_right, -0.15 * (cl.refdef.fov_x - 90), offset_right);
1215 	}
1216 	else
1217 		offset_down[0] = offset_down[1] = offset_down[2] = offset_right[0] = offset_right[1] = offset_right[2] = 0;
1218 
1219 	// set up gun position
1220 	for (i=0 ; i<3 ; i++)
1221 	{
1222 		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
1223 			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
1224 		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
1225 			ps->gunangles[i], cl.lerpfrac);
1226 	}
1227 
1228 	gun.frame = ps->gunframe;
1229 	if (gun.frame == 0)
1230 		gun.oldframe = 0;	// just changed weapons, don't lerp from old
1231 	else
1232 		gun.oldframe = ops->gunframe;
1233 
1234 	VectorSubtract(gun.origin, offset_down, gun.origin);
1235 	VectorSubtract(gun.origin, offset_right, gun.origin);
1236 
1237 	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
1238 	gun.backlerp = 1.0 - cl.lerpfrac;
1239 	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
1240 
1241 	//add an attached muzzleflash for chaingun
1242 	if(!(strcmp("models/weapons/v_shotg2/tris.md2", gun.model->name)))
1243 	{
1244 		if(gun.frame > 4 && gun.frame < 14)
1245 			CL_MuzzleFlashParticle(gun.origin, gun.angles, true);
1246 	}
1247 	else if(!(strcmp("models/weapons/v_hyperb/tris.md2", gun.model->name)))
1248 	{
1249 		if(gun.frame > 5 && gun.frame < 7) {
1250 			CL_PlasmaFlashParticle(gun.origin, gun.angles, true);
1251 			useFX = true;
1252 		}
1253 	}
1254 
1255 	V_AddViewEntity (&gun);
1256 	//add shells for viewweaps (all of em!)
1257 	{
1258 		int oldeffects = gun.flags, pnum;
1259 		entity_state_t	*s1;
1260 
1261 		for (pnum = 0 ; pnum<cl.frame.num_entities ; pnum++)
1262 			if ((s1=&cl_parse_entities[(cl.frame.parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)])->number == cl.playernum+1)
1263 			{
1264 				int effects = s1->renderfx;
1265 
1266 				if (effects & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN) || s1->effects&(EF_PENT|EF_QUAD) || useFX)
1267 				{
1268 					if (effects & RF_SHELL_RED)
1269 						gun.flags |= RF_SHELL_RED;
1270 					if (effects & RF_SHELL_BLUE)
1271 						gun.flags |= RF_SHELL_BLUE;
1272 					if (effects & RF_SHELL_GREEN)
1273 						gun.flags |= RF_SHELL_GREEN;
1274 
1275 					if (useFX)
1276 						gun.flags |= RF_SHELL_GREEN;
1277 
1278 					gun.flags |= RF_TRANSLUCENT;
1279 					gun.alpha = 0.30;
1280 
1281 					if ( ( s1->effects & EF_COLOR_SHELL && gun.flags & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN) ) || useFX)
1282 					{
1283 						V_AddViewEntity (&gun);
1284 					}
1285 					if (s1->effects & EF_PENT)
1286 					{
1287 						gun.flags = oldeffects | RF_TRANSLUCENT | RF_SHELL_RED;
1288 
1289 
1290 						V_AddViewEntity (&gun);
1291 					}
1292 					if (s1->effects & EF_QUAD && cl_gun->value)
1293 					{
1294 						gun.flags = oldeffects | RF_TRANSLUCENT | RF_SHELL_BLUE;
1295 
1296 						V_AddViewEntity (&gun);
1297 					}
1298 				}
1299 			}
1300 
1301 		gun.flags = oldeffects;
1302 	}
1303 
1304 	//add glass pieces
1305 
1306 	if(!(strcmp("models/weapons/v_rocket/tris.md2", gun.model->name)))
1307 	{
1308 		gun.model = R_RegisterModel("models/weapons/v_rocket/cover.md2");
1309 		gun.flags |= RF_TRANSLUCENT;
1310 		gun.alpha = 0.30;
1311 		V_AddViewEntity (&gun);
1312 	}
1313 	if(!(strcmp("models/weapons/v_hyperb/tris.md2", gun.model->name)))
1314 	{
1315 		gun.model = R_RegisterModel("models/weapons/v_hyperb/cover.md2");
1316 		gun.flags |= RF_TRANSLUCENT;
1317 		gun.alpha = 0.30;
1318 		V_AddViewEntity (&gun);
1319 	}
1320 	if(!(strcmp("models/weapons/v_blast/tris.md2", gun.model->name)))
1321 	{
1322 		gun.model = R_RegisterModel("models/weapons/v_blast/cover.md2");
1323 		gun.flags |= RF_TRANSLUCENT;
1324 		gun.alpha = 0.30;
1325 		V_AddViewEntity (&gun);
1326 	}
1327 	if(!(strcmp("models/weapons/v_alienblast/tris.md2", gun.model->name)))
1328 	{
1329 		gun.model = R_RegisterModel("models/weapons/v_alienblast/cover.md2");
1330 		gun.flags |= RF_TRANSLUCENT;
1331 		gun.alpha = 0.30;
1332 		V_AddViewEntity (&gun);
1333 	}
1334 }
1335 
1336 
1337 /*
1338 ===============
1339 CL_CalcViewValues
1340 
1341 Sets cl.refdef view values
1342 ===============
1343 */
CL_CalcViewValues(void)1344 void CL_CalcViewValues (void)
1345 {
1346 	int			i;
1347 	float		lerp, backlerp;
1348 	centity_t	*ent;
1349 	frame_t		*oldframe;
1350 	player_state_t	*ps, *ops;
1351 
1352 	// find the previous frame to interpolate from
1353 	ps = &cl.frame.playerstate;
1354 	i = (cl.frame.serverframe - 1) & UPDATE_MASK;
1355 	oldframe = &cl.frames[i];
1356 	if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
1357 		oldframe = &cl.frame;		// previous frame was dropped or involid
1358 	ops = &oldframe->playerstate;
1359 
1360 	// see if the player entity was teleported this frame
1361 	if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
1362 		|| abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
1363 		|| abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
1364 		ops = ps;		// don't interpolate
1365 
1366 	ent = &cl_entities[cl.playernum+1];
1367 	lerp = cl.lerpfrac;
1368 
1369 	// calculate the origin
1370 	if ( !cl.attractloop && !ps->stats[STAT_CHASE] && cl_predict->value && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))  //not for demo/chasecam
1371 	{	// use predicted values
1372 		unsigned	delta;
1373 
1374 		backlerp = 1.0 - lerp;
1375 		for (i=0 ; i<3 ; i++)
1376 		{
1377 			cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
1378 				+ cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
1379 				- backlerp * cl.prediction_error[i];
1380 		}
1381 
1382 		// smooth out stair climbing
1383 		delta = cls.realtime - cl.predicted_step_time;
1384 		if (delta < 100)
1385 			cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
1386 	}
1387 	else
1388 	{	// just use interpolated values
1389 		for (i=0 ; i<3 ; i++)
1390 			cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
1391 				+ lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
1392 				- (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
1393 	}
1394 
1395 	// if not running a demo or on a locked frame, add the local angle movement
1396 	if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
1397 	{	// use predicted values
1398 		for (i=0 ; i<3 ; i++)
1399 			cl.refdef.viewangles[i] = cl.predicted_angles[i];
1400 	}
1401 	else
1402 	{	// just use interpolated values
1403 		for (i=0 ; i<3 ; i++)
1404 			cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
1405 	}
1406 
1407 	for (i=0 ; i<3 ; i++)
1408 		cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
1409 
1410 	AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
1411 
1412 	// interpolate field of view
1413 	cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
1414 
1415 	// don't interpolate blend color
1416 	for (i=0 ; i<4 ; i++)
1417 		cl.refdef.blend[i] = ps->blend[i];
1418 
1419 	// add the weapon
1420 	CL_AddViewWeapon (ps, ops);
1421 }
1422 
1423 /*
1424 ===============
1425 CL_AddEntities
1426 
1427 Emits all entities, particles, and lights to the refresh
1428 ===============
1429 */
CL_AddEntities(void)1430 void CL_AddEntities (void)
1431 {
1432 	if (cls.state != ca_active)
1433 		return;
1434 
1435 	if (cl.time > cl.frame.servertime)
1436 	{
1437 		if (cl_showclamp->value)
1438 			Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
1439 		cl.time = cl.frame.servertime;
1440 		cl.lerpfrac = 1.0;
1441 	}
1442 	else if (cl.time < cl.frame.servertime - 100)
1443 	{
1444 		if (cl_showclamp->value)
1445 			Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
1446 		cl.time = cl.frame.servertime - 100;
1447 		cl.lerpfrac = 0;
1448 	}
1449 	else
1450 		cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
1451 
1452 	if (cl_timedemo->value)
1453 		cl.lerpfrac = 1.0;
1454 
1455 	CL_CalcViewValues ();
1456 
1457 	// PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
1458 	CL_AddPacketEntities (&cl.frame);
1459 	CL_AddTEnts ();
1460 	CL_AddParticles ();
1461 	CL_AddDLights ();
1462 	CL_AddClEntities();
1463 	CL_AddLightStyles ();
1464 }
1465 
1466 
1467 
1468 /*
1469 ===============
1470 CL_GetEntitySoundOrigin
1471 
1472 Called to get the sound spatialization origin
1473 ===============
1474 */
CL_GetEntitySoundOrigin(int ent,vec3_t org)1475 void CL_GetEntitySoundOrigin (int ent, vec3_t org)
1476 {
1477 	centity_t	*old;
1478 
1479 	if (ent < 0 || ent >= MAX_EDICTS)
1480 		Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
1481 	old = &cl_entities[ent];
1482 	VectorCopy (old->lerp_origin, org);
1483 
1484 	// FIXME: bmodel issues...
1485 }
1486 
1487 /*
1488 ================
1489 Client side entities(ejecting brass, etc
1490 ================
1491 */
1492 
1493 /*
1494 -----------------------------
1495 ClipMoveEntitiesWorld
1496 -----------------------------
1497 */
CL_ClipMoveToEntitiesWorld(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,trace_t * tr,int mask)1498 void CL_ClipMoveToEntitiesWorld(vec3_t start, vec3_t mins, vec3_t maxs,
1499 								vec3_t end, trace_t * tr, int mask)
1500 {
1501 	int i;
1502 	trace_t trace;
1503 	int headnode;
1504 	float *angles;
1505 	entity_state_t *ent;
1506 	int num;
1507 	cmodel_t *cmodel;
1508 
1509 	for (i = 0; i < cl.frame.num_entities; i++) {
1510 		num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
1511 		ent = &cl_parse_entities[num];
1512 
1513 		if (!ent->solid)
1514 			continue;
1515 
1516 		if (ent->solid != 31)	// special value for bmodel
1517 			continue;
1518 
1519 		cmodel = cl.model_clip[ent->modelindex];
1520 		if (!cmodel)
1521 			continue;
1522 		headnode = cmodel->headnode;
1523 		angles = ent->angles;
1524 
1525 		if (tr->allsolid)
1526 			return;
1527 
1528 		trace =
1529 			CM_TransformedBoxTrace(start, end, mins, maxs, headnode, mask,
1530 								   ent->origin, angles);
1531 
1532 		if (trace.allsolid || trace.startsolid
1533 			|| trace.fraction < tr->fraction) {
1534 			trace.ent = (struct edict_s *) ent;
1535 			if (tr->startsolid) {
1536 				*tr = trace;
1537 				tr->startsolid = true;
1538 			} else
1539 				*tr = trace;
1540 		} else if (trace.startsolid)
1541 			tr->startsolid = true;
1542 	}
1543 }
1544 
1545 
CL_PMTraceWorld(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int mask)1546 trace_t CL_PMTraceWorld(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
1547 						int mask)
1548 {
1549 	trace_t t;
1550 
1551 	// check against world
1552 	t = CM_BoxTrace(start, end, mins, maxs, 0, mask);
1553 	if (t.fraction < 1.0)
1554 		t.ent = (struct edict_s *) 1;
1555 
1556 	// check all other solid models
1557 	CL_ClipMoveToEntitiesWorld(start, mins, maxs, end, &t, mask);
1558 
1559 	return t;
1560 }
1561 
VectorReflect(const vec3_t v,const vec3_t normal,vec3_t out)1562 void VectorReflect(const vec3_t v, const vec3_t normal, vec3_t out)
1563 {
1564 	float d;
1565 
1566 	d = 2.0 * (v[0] * normal[0] + v[1] * normal[1] + v[2] * normal[2]);
1567 
1568 	out[0] = v[0] - normal[0] * d;
1569 	out[1] = v[1] - normal[1] * d;
1570 	out[2] = v[2] - normal[2] * d;
1571 }
1572 
1573 extern int CL_PMpointcontents (vec3_t point);
CL_AddClEntities()1574 void CL_AddClEntities()
1575 {
1576 	entity_t ent;
1577 	clentity_t *le, *next;
1578 	clentity_t *active, *tail;
1579 	vec3_t org, dir;
1580 	float alpha, bak;
1581 	int contents;
1582 	qboolean onground;
1583 	char soundname[64];
1584 	float time, time2, grav = Cvar_VariableValue("sv_gravity");
1585 	static vec3_t mins = { -2, -2, -2 };
1586     static vec3_t maxs = { 2, 2, 2 };
1587 
1588 	if (!grav)
1589 		grav = 1;
1590 	else
1591 		grav /= 800;
1592 
1593 	active = NULL;
1594 	tail = NULL;
1595 
1596 	memset(&ent, 0, sizeof(ent));
1597 
1598 	for (le = active_clentities; le; le = next) {
1599 		next = le->next;
1600 
1601 		time = (cl.time - le->time) * 0.001;
1602 		alpha = le->alpha + time * le->alphavel;
1603 
1604 		if (alpha <= 0) {		// faded out
1605 			le->next = free_clentities;
1606 			free_clentities = le;
1607 			continue;
1608 		}
1609 
1610 		time2 = time * time;
1611 		org[0] = le->org[0] + le->vel[0] * time + le->accel[0] * time2;
1612 		org[1] = le->org[1] + le->vel[1] * time + le->accel[1] * time2;
1613 		bak = le->org[2] + le->vel[2] * time + le->accel[2] * time2 * grav;
1614 
1615 		org[2] = bak - 1;
1616 		contents = CL_PMpointcontents(org);
1617 		org[2] = bak;
1618 		onground = contents & MASK_SOLID;
1619 		if (onground) {
1620 			le->flags &= ~CLM_ROTATE;
1621 			le->avel = 0;
1622 		} else if (le->flags & CLM_STOPPED) {
1623 			le->flags &= ~CLM_STOPPED;
1624 			le->flags |= CLM_BOUNCE;
1625 			le->accel[2] = -15 * PARTICLE_GRAVITY;
1626 			// Reset
1627 			le->alpha = 1;
1628 			le->time = cl.time;
1629 			VectorCopy(org, le->org);
1630 		}
1631 
1632 		le->next = NULL;
1633 		if (!tail)
1634 			active = tail = le;
1635 		else {
1636 			tail->next = le;
1637 			tail = le;
1638 		}
1639 
1640 		if (alpha > 1.0)
1641 			alpha = 1;
1642 
1643 		if(le->flags & CLM_NOSHADOW)
1644 			ent.flags |= RF_NOSHADOWS;
1645 
1646 		if (le->flags & CLM_FRICTION) {
1647 			// Water friction affected cl model
1648 			if (contents & MASK_WATER) {
1649 				if (contents & CONTENTS_LAVA) {	// kill entity in lava
1650 					VectorSet(dir, 0, 0, 1);
1651 					le->alpha = 0;
1652 					continue;
1653 				} else {
1654 					// Add friction
1655 					VectorScale(le->vel, 0.25, le->vel);
1656 					VectorScale(le->accel, 0.25, le->accel);
1657 
1658 					// Don't add friction again
1659 					le->flags &= ~(CLM_FRICTION | CLM_ROTATE);
1660 
1661 					// Reset
1662 					le->time = cl.time;
1663 					VectorCopy(org, le->org);
1664 				}
1665 			}
1666 		}
1667 
1668 		if (le->flags & CLM_BOUNCE)
1669 		{
1670 			trace_t trace = CL_PMTraceWorld (le->lastOrg, mins, maxs, org, MASK_SOLID);
1671 
1672 			if (trace.fraction > 0.0001f && trace.fraction < 0.9999f )
1673 			{
1674 				vec3_t	vel;
1675 				// Reflect velocity
1676 				float time =
1677 					cl.time - (cls.frametime +
1678 							   cls.frametime * trace.fraction) * 1000;
1679 				time = (time - le->time) * 0.001;
1680 
1681 				VectorSet(vel, le->vel[0], le->vel[1], le->vel[2] + le->accel[2] * time * grav);
1682 				VectorReflect(vel, trace.plane.normal, le->vel);
1683 
1684 				// Check for stop or slide along the plane
1685 				if (trace.plane.normal[2] > 0 && le->vel[2] < 1)
1686 				{
1687 					if (trace.plane.normal[2] > 0.9)
1688 					{
1689 						VectorClear(le->vel);
1690 						VectorClear(le->accel);
1691 						le->avel = 0;
1692 						le->flags &= ~CLM_BOUNCE;
1693 						le->flags |= CLM_STOPPED;
1694 					}
1695 					else
1696 					{
1697 						// FIXME: check for new plane or free fall
1698 						float dot = DotProduct(le->vel, trace.plane.normal);
1699 						VectorMA(le->vel, -dot, trace.plane.normal, le->vel);
1700 
1701 						dot = DotProduct(le->accel, trace.plane.normal);
1702 						VectorMA(le->accel, -dot, trace.plane.normal, le->accel);
1703 					}
1704 				}
1705 
1706 				VectorCopy(trace.endpos, org);
1707 
1708 				// Reset
1709 				le->time = cl.time;
1710 				VectorCopy(org, le->org);
1711 
1712 				//play a sound if brass
1713 				if ( (le->flags & (CLM_BRASS))  &&  (le->flags & (CLM_BOUNCE)) ) {
1714 					Com_sprintf(soundname, sizeof(soundname), "weapons/clink0%i.wav", (rand() % 2) + 1);
1715 					S_StartSound (le->org, 0, CHAN_WEAPON, S_RegisterSound(soundname), 1.0, ATTN_NORM, 0);
1716 				}
1717 
1718 				//play a sound if glass
1719 				if ( (le->flags & (CLM_GLASS))  &&  (le->flags & (CLM_BOUNCE)) ) {
1720 					Com_sprintf(soundname, sizeof(soundname), "weapons/clink0%i.wav", (rand() % 2) + 1); //to do - get glass sound
1721 					S_StartSound (le->org, 0, CHAN_WEAPON, S_RegisterSound(soundname), 1.0, ATTN_NORM, 0);
1722 				}
1723 			}
1724 		}
1725 		// Save current origin if needed
1726 		if (le->flags & (CLM_BOUNCE)) {
1727 			VectorCopy(le->lastOrg, ent.origin);
1728 			VectorCopy(org, le->lastOrg);	// FIXME: pause
1729 		} else
1730 			VectorCopy(org, ent.origin);
1731 
1732 		if (CL_PMpointcontents(ent.origin) & MASK_SOLID) {	// kill entity
1733 															// in solid
1734 			le->alpha = 0;
1735 			continue;
1736 		}
1737 
1738 		ent.model = le->model;
1739 		if (!ent.model)
1740 			continue;
1741 
1742 		ent.lod1 = NULL;
1743 		ent.lod2 = NULL;
1744 
1745 		ent.angles[0] = le->ang +
1746 			((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);;
1747 		ent.angles[2] = le->ang +
1748 			((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);;
1749 		ent.angles[1] =
1750 			le->ang +
1751 			((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);
1752 
1753 		ent.frame = ent.oldframe = 0;
1754 
1755 		if(le->flags & CLM_GLASS)
1756 			ent.flags |= RF_TRANSLUCENT;
1757 
1758 		V_AddEntity(&ent);
1759 
1760 	}
1761 
1762 	active_clentities = active;
1763 }
1764 
CL_ClearClEntities()1765 void CL_ClearClEntities()
1766 {
1767 	int i;
1768 
1769 	free_clentities = &clentities[0];
1770 	active_clentities = NULL;
1771 
1772 	for (i = 0; i < MAX_CLENTITIES-1; i++)
1773 		clentities[i].next = &clentities[i + 1];
1774 	clentities[MAX_CLENTITIES - 1].next = NULL;
1775 }
1776