1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 
21 */
22 // cl_main.c  -- client main loop
23 
24 #include "quakedef.h"
25 #include "bgmusic.h"
26 
27 // we need to declare some mouse variables here, because the menu system
28 // references them even when on a unix system.
29 
30 // these two are not intended to be set directly
31 cvar_t	cl_name = {"_cl_name", "player", CVAR_ARCHIVE};
32 cvar_t	cl_color = {"_cl_color", "0", CVAR_ARCHIVE};
33 
34 cvar_t	cl_shownet = {"cl_shownet","0",CVAR_NONE};	// can be 0, 1, or 2
35 cvar_t	cl_nolerp = {"cl_nolerp","0",CVAR_NONE};
36 
37 cvar_t	cfg_unbindall = {"cfg_unbindall", "1", CVAR_ARCHIVE};
38 
39 cvar_t	lookspring = {"lookspring","0", CVAR_ARCHIVE};
40 cvar_t	lookstrafe = {"lookstrafe","0", CVAR_ARCHIVE};
41 cvar_t	sensitivity = {"sensitivity","3", CVAR_ARCHIVE};
42 
43 cvar_t	m_pitch = {"m_pitch","0.022", CVAR_ARCHIVE};
44 cvar_t	m_yaw = {"m_yaw","0.022", CVAR_ARCHIVE};
45 cvar_t	m_forward = {"m_forward","1", CVAR_ARCHIVE};
46 cvar_t	m_side = {"m_side","0.8", CVAR_ARCHIVE};
47 
48 cvar_t	cl_maxpitch = {"cl_maxpitch", "90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
49 cvar_t	cl_minpitch = {"cl_minpitch", "-90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
50 
51 client_static_t	cls;
52 client_state_t	cl;
53 // FIXME: put these on hunk?
54 lightstyle_t	cl_lightstyle[MAX_LIGHTSTYLES];
55 dlight_t		cl_dlights[MAX_DLIGHTS];
56 
57 int				cl_numvisedicts;
58 int				cl_maxvisedicts;
59 entity_t		**cl_visedicts;
60 
61 extern cvar_t	r_lerpmodels, r_lerpmove; //johnfitz
62 extern float	host_netinterval;	//Spike
63 
64 #ifdef PSET_SCRIPT
CL_ClearTrailStates(void)65 void CL_ClearTrailStates(void)
66 {
67 	int i;
68 	for (i = 0; i < cl.num_statics; i++)
69 	{
70 		PScript_DelinkTrailstate(&(cl.static_entities[i]->trailstate));
71 		PScript_DelinkTrailstate(&(cl.static_entities[i]->emitstate));
72 	}
73 	for (i = 0; i < cl.max_edicts; i++)
74 	{
75 		PScript_DelinkTrailstate(&(cl.entities[i].trailstate));
76 		PScript_DelinkTrailstate(&(cl.entities[i].emitstate));
77 	}
78 	for (i = 0; i < MAX_BEAMS; i++)
79 	{
80 		PScript_DelinkTrailstate(&(cl_beams[i].trailstate));
81 	}
82 }
83 #endif
84 
CL_FreeState(void)85 void CL_FreeState(void)
86 {
87 	int i;
88 	for (i = 0; i < MAX_CL_STATS; i++)
89 		free(cl.statss[i]);
90 	PR_ClearProgs(&cl.qcvm);
91 	free(cl.static_entities);
92 	memset (&cl, 0, sizeof(cl));
93 }
94 
95 /*
96 =====================
97 CL_ClearState
98 
99 =====================
100 */
CL_ClearState(void)101 void CL_ClearState (void)
102 {
103 	if (!sv.active)
104 		Host_ClearMemory ();
105 
106 // wipe the entire cl structure
107 	CL_FreeState();
108 
109 	SZ_Clear (&cls.message);
110 
111 // clear other arrays
112 	memset (cl_dlights, 0, sizeof(cl_dlights));
113 	memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
114 	memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
115 	memset (cl_beams, 0, sizeof(cl_beams));
116 
117 	//johnfitz -- cl_entities is now dynamically allocated
118 	cl.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
119 	cl.entities = (entity_t *) Hunk_AllocName (cl.max_edicts*sizeof(entity_t), "cl_entities");
120 	//johnfitz
121 
122 	//Spike -- this stuff needs to get reset to defaults.
123 #ifdef PSET_SCRIPT
124 	PScript_Shutdown();
125 #endif
126 }
127 
128 /*
129 =====================
130 CL_Disconnect
131 
132 Sends a disconnect message to the server
133 This is also called on Host_Error, so it shouldn't cause any errors
134 =====================
135 */
CL_Disconnect(void)136 void CL_Disconnect (void)
137 {
138 	if (key_dest == key_message)
139 		Key_EndChat ();	// don't get stuck in chat mode
140 
141 // stop sounds (especially looping!)
142 	S_StopAllSounds (true);
143 	BGM_Stop();
144 	CDAudio_Stop();
145 
146 // if running a local server, shut it down
147 	if (cls.demoplayback)
148 		CL_StopPlayback ();
149 	else if (cls.state == ca_connected)
150 	{
151 		if (cls.demorecording)
152 			CL_Stop_f ();
153 
154 		Con_DPrintf ("Sending clc_disconnect\n");
155 		SZ_Clear (&cls.message);
156 		MSG_WriteByte (&cls.message, clc_disconnect);
157 		NET_SendUnreliableMessage (cls.netcon, &cls.message);
158 		SZ_Clear (&cls.message);
159 		NET_Close (cls.netcon);
160 		cls.netcon = NULL;
161 
162 		cls.state = ca_disconnected;
163 		if (sv.active)
164 			Host_ShutdownServer(false);
165 	}
166 
167 	cls.demoplayback = cls.timedemo = false;
168 	cls.demopaused = false;
169 	cls.signon = 0;
170 	cls.netcon = NULL;
171 	cl.intermission = 0;
172 	cl.worldmodel = NULL;
173 	cl.sendprespawn = false;
174 }
175 
CL_Disconnect_f(void)176 void CL_Disconnect_f (void)
177 {
178 	CL_Disconnect ();
179 	if (sv.active)
180 		Host_ShutdownServer (false);
181 }
182 
183 
184 /*
185 =====================
186 CL_EstablishConnection
187 
188 Host should be either "local" or a net address to be passed on
189 =====================
190 */
CL_EstablishConnection(const char * host)191 void CL_EstablishConnection (const char *host)
192 {
193 	if (cls.state == ca_dedicated)
194 		return;
195 
196 	if (cls.demoplayback)
197 		return;
198 
199 	CL_Disconnect ();
200 
201 	cls.netcon = NET_Connect (host);
202 	if (!cls.netcon)
203 		Host_Error ("CL_Connect: connect failed\n");
204 	Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
205 
206 	cls.demonum = -1;			// not in the demo loop now
207 	cls.state = ca_connected;
208 	cls.signon = 0;				// need all the signon messages before playing
209 	MSG_WriteByte (&cls.message, clc_nop);	// NAT Fix from ProQuake
210 }
211 
CL_SendInitialUserinfo(void * ctx,const char * key,const char * val)212 void CL_SendInitialUserinfo(void *ctx, const char *key, const char *val)
213 {
214 	if (*key == '*')
215 		return;	//servers don't like that sort of userinfo key
216 	if (!strcmp(key, "name"))
217 		return;	//already unconditionally sent earlier.
218 	MSG_WriteByte (&cls.message, clc_stringcmd);
219 	MSG_WriteString (&cls.message, va("setinfo \"%s\" \"%s\"\n", key, val));
220 }
221 /*
222 =====================
223 CL_SignonReply
224 
225 An svc_signonnum has been received, perform a client side setup
226 =====================
227 */
CL_SignonReply(void)228 void CL_SignonReply (void)
229 {
230 	char 	str[8192];
231 
232 	Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
233 
234 	switch (cls.signon)
235 	{
236 	case 1:
237 		MSG_WriteByte (&cls.message, clc_stringcmd);
238 		MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
239 
240 		cl.sendprespawn = true;
241 		break;
242 
243 	case 2:
244 		if (*cl.serverinfo)
245 			Info_Enumerate(cls.userinfo, CL_SendInitialUserinfo, NULL);
246 
247 		MSG_WriteByte (&cls.message, clc_stringcmd);
248 		sprintf (str, "spawn %s", cls.spawnparms);
249 		MSG_WriteString (&cls.message, str);
250 		break;
251 
252 	case 3:
253 		MSG_WriteByte (&cls.message, clc_stringcmd);
254 		MSG_WriteString (&cls.message, "begin");
255 		Cache_Report ();		// print remaining memory
256 		break;
257 
258 	case 4:
259 		SCR_EndLoadingPlaque ();		// allow normal screen updates
260 		break;
261 	}
262 }
263 
264 
265 /*
266 =====================
267 CL_NextDemo
268 
269 Called to play the next demo in the demo loop
270 =====================
271 */
CL_NextDemo(void)272 void CL_NextDemo (void)
273 {
274 	char	str[1024];
275 
276 	if (cls.demonum == -1)
277 		return;		// don't play demos
278 
279 	if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
280 	{
281 		cls.demonum = 0;
282 		if (!cls.demos[cls.demonum][0])
283 		{
284 			Con_Printf ("No demos listed with startdemos\n");
285 			cls.demonum = -1;
286 			CL_Disconnect();
287 			return;
288 		}
289 	}
290 
291 	SCR_BeginLoadingPlaque ();
292 
293 	sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
294 	Cbuf_InsertText (str);
295 	cls.demonum++;
296 }
297 
298 /*
299 ==============
300 CL_PrintEntities_f
301 ==============
302 */
CL_PrintEntities_f(void)303 void CL_PrintEntities_f (void)
304 {
305 	entity_t	*ent;
306 	int			i;
307 
308 	if (cls.state != ca_connected)
309 		return;
310 
311 	for (i=0,ent=cl.entities ; i<cl.num_entities ; i++,ent++)
312 	{
313 		Con_Printf ("%3i:",i);
314 		if (!ent->model)
315 		{
316 			Con_Printf ("EMPTY\n");
317 			continue;
318 		}
319 		Con_Printf ("%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
320 		,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
321 	}
322 }
323 
324 /*
325 ===============
326 CL_AllocDlight
327 
328 ===============
329 */
CL_AllocDlight(int key)330 dlight_t *CL_AllocDlight (int key)
331 {
332 	int		i;
333 	dlight_t	*dl;
334 
335 // first look for an exact key match
336 	if (key)
337 	{
338 		dl = cl_dlights;
339 		for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
340 		{
341 			if (dl->key == key)
342 			{
343 				memset (dl, 0, sizeof(*dl));
344 				dl->key = key;
345 				dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc
346 				return dl;
347 			}
348 		}
349 	}
350 
351 // then look for anything else
352 	dl = cl_dlights;
353 	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
354 	{
355 		if (dl->die < cl.time)
356 		{
357 			memset (dl, 0, sizeof(*dl));
358 			dl->key = key;
359 			dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc
360 			return dl;
361 		}
362 	}
363 
364 	dl = &cl_dlights[0];
365 	memset (dl, 0, sizeof(*dl));
366 	dl->key = key;
367 	dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc
368 	return dl;
369 }
370 
371 
372 /*
373 ===============
374 CL_DecayLights
375 
376 ===============
377 */
CL_DecayLights(void)378 void CL_DecayLights (void)
379 {
380 	int			i;
381 	dlight_t	*dl;
382 	float		time;
383 
384 	time = cl.time - cl.oldtime;
385 	if (time < 0)
386 		return;
387 
388 	dl = cl_dlights;
389 	for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
390 	{
391 		if (dl->die < cl.time || !dl->radius)
392 			continue;
393 
394 		dl->radius -= time*dl->decay;
395 		if (dl->radius < 0)
396 			dl->radius = 0;
397 	}
398 }
399 
400 
401 /*
402 ===============
403 CL_LerpPoint
404 
405 Determines the fraction between the last two messages that the objects
406 should be put at.
407 ===============
408 */
CL_LerpPoint(void)409 float	CL_LerpPoint (void)
410 {
411 	float	f, frac;
412 
413 	f = cl.mtime[0] - cl.mtime[1];
414 
415 	if (!f || cls.timedemo || (sv.active && !host_netinterval))
416 	{
417 		cl.time = cl.mtime[0];
418 		return 1;
419 	}
420 
421 	if (f > 0.1) // dropped packet, or start of demo
422 	{
423 		cl.mtime[1] = cl.mtime[0] - 0.1;
424 		f = 0.1;
425 	}
426 
427 	frac = (cl.time - cl.mtime[1]) / f;
428 
429 	if (frac < 0)
430 	{
431 		if (frac < -0.01)
432 			cl.time = cl.mtime[1];
433 		frac = 0;
434 	}
435 	else if (frac > 1)
436 	{
437 		if (frac > 1.01)
438 			cl.time = cl.mtime[0];
439 		frac = 1;
440 	}
441 
442 	//johnfitz -- better nolerp behavior
443 	if (cl_nolerp.value)
444 		return 1;
445 	//johnfitz
446 
447 	return frac;
448 }
449 
CL_LerpEntity(entity_t * ent,vec3_t org,vec3_t ang,float frac)450 static qboolean CL_LerpEntity(entity_t *ent, vec3_t org, vec3_t ang, float frac)
451 {
452 	float f, d;
453 	int j;
454 	vec3_t delta;
455 	qboolean teleported = false;
456 	//figure out the pos+angles of the parent
457 	if (ent->forcelink)
458 	{	// the entity was not updated in the last message
459 		// so move to the final spot
460 		VectorCopy (ent->msg_origins[0], org);
461 		VectorCopy (ent->msg_angles[0], ang);
462 	}
463 	else
464 	{	// if the delta is large, assume a teleport and don't lerp
465 		f = frac;
466 		for (j=0 ; j<3 ; j++)
467 		{
468 			delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
469 			if (delta[j] > 100 || delta[j] < -100)
470 			{
471 				f = 1;		// assume a teleportation, not a motion
472 				teleported = true;	//johnfitz -- don't lerp teleports
473 			}
474 		}
475 
476 		//johnfitz -- don't cl_lerp entities that will be r_lerped
477 		if (r_lerpmove.value && (ent->lerpflags & LERP_MOVESTEP))
478 			f = 1;
479 		//johnfitz
480 
481 	// interpolate the origin and angles
482 		for (j=0 ; j<3 ; j++)
483 		{
484 			org[j] = ent->msg_origins[1][j] + f*delta[j];
485 
486 			d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
487 			if (d > 180)
488 				d -= 360;
489 			else if (d < -180)
490 				d += 360;
491 			ang[j] = ent->msg_angles[1][j] + f*d;
492 		}
493 	}
494 	return teleported;
495 }
496 
CL_AttachEntity(entity_t * ent,float frac)497 static qboolean CL_AttachEntity(entity_t *ent, float frac)
498 {
499 	entity_t *parent;
500 	vec3_t porg, pang;
501 	vec3_t paxis[3];
502 	vec3_t tmp, fwd, up;
503 	unsigned int tagent = ent->netstate.tagentity;
504 	int runaway = 0;
505 
506 	while(1)
507 	{
508 		if (!tagent)
509 			return true;	//nothing to do.
510 		if (runaway++==10 || tagent >= (unsigned int)cl.num_entities)
511 			return false;	//parent isn't valid
512 		parent = &cl.entities[tagent];
513 
514 		if (tagent == cl.viewentity)
515 			ent->eflags |= EFLAGS_EXTERIORMODEL;
516 
517 		if (!parent->model)
518 			return false;
519 		if (0)//tagent < ent-cl_entities)
520 		{
521 			tagent = parent->netstate.tagentity;
522 			VectorCopy(parent->origin, porg);
523 			VectorCopy(parent->angles, pang);
524 		}
525 		else
526 		{
527 			tagent = parent->netstate.tagentity;
528 			CL_LerpEntity(parent, porg, pang, frac);
529 		}
530 
531 		//FIXME: this code needs to know the exact lerp info of the underlaying model.
532 		//however for some idiotic reason, someone decided to figure out what should be displayed somewhere far removed from the code that deals with timing
533 		//so we have absolutely no way to get a reliable origin
534 		//in the meantime, r_lerpmove 0; r_lerpmodels 0
535 		//you might be able to work around it by setting the attached entity to movetype_step to match the attachee, and to avoid EF_MUZZLEFLASH.
536 		//personally I'm just going to call it a quakespasm bug that I cba to fix.
537 
538 		//FIXME: update porg+pang according to the tag index (we don't support md3s/iqms, so we don't need to do anything here yet)
539 
540 		if (parent->model && parent->model->type == mod_alias)
541 			pang[0] *= -1;
542 		AngleVectors(pang, paxis[0], paxis[1], paxis[2]);
543 
544 		if (ent->model && ent->model->type == mod_alias)
545 			ent->angles[0] *= -1;
546 		AngleVectors(ent->angles, fwd, tmp, up);
547 
548 		//transform the origin
549 		VectorMA(parent->origin, ent->origin[0], paxis[0], tmp);
550 		VectorMA(tmp, -ent->origin[1], paxis[1], tmp);
551 		VectorMA(tmp, ent->origin[2], paxis[2], ent->origin);
552 
553 		//transform the forward vector
554 		VectorMA(vec3_origin, fwd[0], paxis[0], tmp);
555 		VectorMA(tmp, -fwd[1], paxis[1], tmp);
556 		VectorMA(tmp, fwd[2], paxis[2], fwd);
557 		//transform the up vector
558 		VectorMA(vec3_origin, up[0], paxis[0], tmp);
559 		VectorMA(tmp, -up[1], paxis[1], tmp);
560 		VectorMA(tmp, up[2], paxis[2], up);
561 		//regenerate the new angles.
562 		VectorAngles(fwd, up, ent->angles);
563 		if (ent->model && ent->model->type == mod_alias)
564 			ent->angles[0] *= -1;
565 
566 		ent->eflags |= parent->netstate.eflags & (EFLAGS_VIEWMODEL|EFLAGS_EXTERIORMODEL);
567 	}
568 }
569 
570 /*
571 ===============
572 CL_RelinkEntities
573 ===============
574 */
CL_RelinkEntities(void)575 void CL_RelinkEntities (void)
576 {
577 	entity_t	*ent;
578 	int			i, j;
579 	float		frac, d;
580 	float		bobjrotate;
581 	vec3_t		oldorg;
582 	dlight_t	*dl;
583 	float		frametime;
584 	int			modelflags;
585 
586 // determine partial update time
587 	frac = CL_LerpPoint ();
588 
589 	frametime = cl.time - cl.oldtime;
590 	if (frametime < 0)
591 		frametime = 0;
592 	if (frametime > 0.1)
593 		frametime = 0.1;
594 
595 	if (cl_numvisedicts + 64 > cl_maxvisedicts)
596 	{
597 		cl_maxvisedicts = cl_maxvisedicts+64;
598 		cl_visedicts = realloc(cl_visedicts, sizeof(*cl_visedicts)*cl_maxvisedicts);
599 	}
600 	cl_numvisedicts = 0;
601 
602 //
603 // interpolate player info
604 //
605 	for (i=0 ; i<3 ; i++)
606 		cl.velocity[i] = cl.mvelocity[1][i] +
607 			frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
608 
609 	if (cls.demoplayback)
610 	{
611 	// interpolate the angles
612 		for (j=0 ; j<3 ; j++)
613 		{
614 			d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
615 			if (d > 180)
616 				d -= 360;
617 			else if (d < -180)
618 				d += 360;
619 			cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;
620 		}
621 	}
622 
623 	bobjrotate = anglemod(100*cl.time);
624 
625 // start on the entity after the world
626 	ent = (cl.entities != NULL) ? (cl.entities + 1) : NULL;
627 	for (i=1; i<cl.num_entities ; i++,ent++)
628 	{
629 		if (!ent->model)
630 		{	// empty slot, ish.
631 
632 			// ericw -- efrags are only used for static entities in GLQuake
633 			// ent can't be static, so this is a no-op.
634 			//if (ent->forcelink)
635 			//	R_RemoveEfrags (ent);	// just became empty
636 			continue;
637 		}
638 		ent->eflags = ent->netstate.eflags;
639 
640 // if the object wasn't included in the last packet, remove it
641 		if (ent->msgtime != cl.mtime[0])
642 		{
643 			ent->model = NULL;
644 			ent->lerpflags |= LERP_RESETMOVE|LERP_RESETANIM; //johnfitz -- next time this entity slot is reused, the lerp will need to be reset
645 			InvalidateTraceLineCache();
646 			continue;
647 		}
648 
649 		VectorCopy (ent->origin, oldorg);
650 
651 		if (CL_LerpEntity(ent, ent->origin, ent->angles, frac))
652 			ent->lerpflags |= LERP_RESETMOVE;
653 
654 		if (ent->netstate.tagentity)
655 		if (!CL_AttachEntity(ent, frac))
656 		{
657 			//can't draw it if we don't know where its parent is.
658 			continue;
659 		}
660 
661 		modelflags = (ent->effects>>24)&0xff;
662 		modelflags |= ent->model->flags;
663 
664 // rotate binary objects locally
665 		if (modelflags & EF_ROTATE)
666 			ent->angles[1] = bobjrotate;
667 
668 		if (ent->effects & EF_BRIGHTFIELD)
669 			R_EntityParticles (ent);
670 
671 		if (ent->effects & EF_MUZZLEFLASH)
672 		{
673 			vec3_t		fv, rv, uv;
674 
675 			dl = CL_AllocDlight (i);
676 			VectorCopy (ent->origin,  dl->origin);
677 			dl->origin[2] += 16;
678 			AngleVectors (ent->angles, fv, rv, uv);
679 
680 			VectorMA (dl->origin, 18, fv, dl->origin);
681 			dl->radius = 200 + (rand()&31);
682 			dl->minlight = 32;
683 			dl->die = cl.time + 0.1;
684 
685 			//johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped
686 			if (r_lerpmodels.value != 2)
687 			{
688 				if (ent == &cl.entities[cl.viewentity])
689 					cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
690 				else
691 				ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
692 			}
693 			//johnfitz
694 		}
695 		if (ent->effects & EF_BRIGHTLIGHT)
696 		{
697 			dl = CL_AllocDlight (i);
698 			VectorCopy (ent->origin,  dl->origin);
699 			dl->origin[2] += 16;
700 			dl->radius = 400 + (rand()&31);
701 			dl->die = cl.time + 0.001;
702 		}
703 		if (ent->effects & EF_DIMLIGHT)
704 		{
705 			dl = CL_AllocDlight (i);
706 			VectorCopy (ent->origin,  dl->origin);
707 			dl->radius = 200 + (rand()&31);
708 			dl->die = cl.time + 0.001;
709 		}
710 
711 #ifdef PSET_SCRIPT
712 		if (cl.paused)
713 			;
714 		else if (ent->netstate.traileffectnum > 0 && ent->netstate.traileffectnum < MAX_PARTICLETYPES)
715 		{
716 			vec3_t axis[3];
717 			AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
718 			PScript_ParticleTrail(oldorg, ent->origin, cl.particle_precache[ent->netstate.traileffectnum].index, frametime, i, axis, &ent->trailstate);
719 		}
720 		else if (ent->model->traileffect >= 0)
721 		{
722 			vec3_t axis[3];
723 			AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
724 			PScript_ParticleTrail(oldorg, ent->origin, ent->model->traileffect, frametime, i, axis, &ent->trailstate);
725 		}
726 		else
727 #endif
728 		if (ent->model->flags & EF_GIB)
729 			R_RocketTrail (oldorg, ent->origin, 2);
730 		else if (ent->model->flags & EF_ZOMGIB)
731 			R_RocketTrail (oldorg, ent->origin, 4);
732 		else if (ent->model->flags & EF_TRACER)
733 			R_RocketTrail (oldorg, ent->origin, 3);
734 		else if (ent->model->flags & EF_TRACER2)
735 			R_RocketTrail (oldorg, ent->origin, 5);
736 		else if (ent->model->flags & EF_ROCKET)
737 		{
738 			R_RocketTrail (oldorg, ent->origin, 0);
739 			dl = CL_AllocDlight (i);
740 			VectorCopy (ent->origin, dl->origin);
741 			dl->radius = 200;
742 			dl->die = cl.time + 0.01;
743 		}
744 		else if (ent->model->flags & EF_GRENADE)
745 			R_RocketTrail (oldorg, ent->origin, 1);
746 		else if (ent->model->flags & EF_TRACER3)
747 			R_RocketTrail (oldorg, ent->origin, 6);
748 
749 		ent->forcelink = false;
750 
751 #ifdef PSET_SCRIPT
752 		if (ent->netstate.emiteffectnum > 0)
753 		{
754 			vec3_t axis[3];
755 			AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
756 			if (ent->model->type == mod_alias)
757 				axis[0][2] *= -1;	//stupid vanilla bug
758 			PScript_RunParticleEffectState(ent->origin, axis[0], frametime, cl.particle_precache[ent->netstate.emiteffectnum].index, &ent->emitstate);
759 		}
760 		else if (ent->model->emiteffect >= 0)
761 		{
762 			vec3_t axis[3];
763 			AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
764 			if (ent->model->flags & MOD_EMITFORWARDS)
765 			{
766 				if (ent->model->type == mod_alias)
767 					axis[0][2] *= -1;	//stupid vanilla bug
768 			}
769 			else
770 				VectorScale(axis[2], -1, axis[0]);
771 			PScript_RunParticleEffectState(ent->origin, axis[0], frametime, ent->model->emiteffect, &ent->emitstate);
772 			if (ent->model->flags & MOD_EMITREPLACE)
773 				continue;
774 		}
775 #endif
776 
777 		if (i == cl.viewentity && !chase_active.value)
778 			continue;
779 
780 		if (cl_numvisedicts < cl_maxvisedicts)
781 		{
782 			cl_visedicts[cl_numvisedicts] = ent;
783 			cl_numvisedicts++;
784 		}
785 	}
786 
787 	//johnfitz -- lerping
788 	//ericw -- this was done before the upper 8 bits of cl.stats[STAT_WEAPON] were filled in, breaking on large maps like zendar.bsp
789 	if (cl.viewent.model != cl.model_precache[cl.stats[STAT_WEAPON]])
790 	{
791 		cl.viewent.lerpflags |= LERP_RESETANIM; //don't lerp animation across model changes
792 	}
793 	//johnfitz
794 }
795 
796 #ifdef PSET_SCRIPT
CL_GenerateRandomParticlePrecache(const char * pname)797 int CL_GenerateRandomParticlePrecache(const char *pname)
798 {	//for dpp7 compat
799 	size_t i;
800 	pname = va("%s", pname);
801 	for (i = 1; i < MAX_PARTICLETYPES; i++)
802 	{
803 		if (!cl.particle_precache[i].name)
804 		{
805 			cl.particle_precache[i].name = strcpy(Hunk_Alloc(strlen(pname)+1), pname);
806 			cl.particle_precache[i].index = PScript_FindParticleType(cl.particle_precache[i].name);
807 			return i;
808 		}
809 		if (!strcmp(cl.particle_precache[i].name, pname))
810 			return i;
811 	}
812 	return 0;
813 }
814 #endif
815 
816 
817 /*
818 ===============
819 CL_ReadFromServer
820 
821 Read all incoming data from the server
822 ===============
823 */
CL_ReadFromServer(void)824 int CL_ReadFromServer (void)
825 {
826 	int			ret;
827 	extern int	num_temp_entities; //johnfitz
828 	int			num_beams = 0; //johnfitz
829 	int			num_dlights = 0; //johnfitz
830 	beam_t		*b; //johnfitz
831 	dlight_t	*l; //johnfitz
832 	int			i; //johnfitz
833 
834 
835 	cl.oldtime = cl.time;
836 	cl.time += host_frametime;
837 
838 	do
839 	{
840 		ret = CL_GetMessage ();
841 		if (ret == -1)
842 			Host_Error ("CL_ReadFromServer: lost server connection");
843 		if (!ret)
844 			break;
845 
846 		cl.last_received_message = realtime;
847 		CL_ParseServerMessage ();
848 	} while (ret && cls.state == ca_connected);
849 
850 	if (cl_shownet.value)
851 		Con_Printf ("\n");
852 
853 	CL_RelinkEntities ();
854 	CL_UpdateTEnts ();
855 
856 //johnfitz -- devstats
857 
858 	//visedicts
859 	if (cl_numvisedicts > 256 && dev_peakstats.visedicts <= 256)
860 		Con_DWarning ("%i visedicts exceeds standard limit of 256.\n", cl_numvisedicts);
861 	dev_stats.visedicts = cl_numvisedicts;
862 	dev_peakstats.visedicts = q_max(cl_numvisedicts, dev_peakstats.visedicts);
863 
864 	//temp entities
865 	if (num_temp_entities > 64 && dev_peakstats.tempents <= 64)
866 		Con_DWarning ("%i tempentities exceeds standard limit of 64 (max = %d).\n", num_temp_entities, MAX_TEMP_ENTITIES);
867 	dev_stats.tempents = num_temp_entities;
868 	dev_peakstats.tempents = q_max(num_temp_entities, dev_peakstats.tempents);
869 
870 	//beams
871 	for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
872 		if (b->model && b->endtime >= cl.time)
873 			num_beams++;
874 	if (num_beams > 24 && dev_peakstats.beams <= 24)
875 		Con_DWarning ("%i beams exceeded standard limit of 24 (max = %d).\n", num_beams, MAX_BEAMS);
876 	dev_stats.beams = num_beams;
877 	dev_peakstats.beams = q_max(num_beams, dev_peakstats.beams);
878 
879 	//dlights
880 	for (i=0, l=cl_dlights ; i<MAX_DLIGHTS ; i++, l++)
881 		if (l->die >= cl.time && l->radius)
882 			num_dlights++;
883 	if (num_dlights > 32 && dev_peakstats.dlights <= 32)
884 		Con_DWarning ("%i dlights exceeded standard limit of 32 (max = %d).\n", num_dlights, MAX_DLIGHTS);
885 	dev_stats.dlights = num_dlights;
886 	dev_peakstats.dlights = q_max(num_dlights, dev_peakstats.dlights);
887 
888 //johnfitz
889 
890 //
891 // bring the links up to date
892 //
893 	return 0;
894 }
895 
896 /*
897 =================
898 CL_UpdateViewAngles
899 
900 Spike: split from CL_SendCmd, to do clientside viewangle changes separately from outgoing packets.
901 =================
902 */
CL_AccumulateCmd(void)903 void CL_AccumulateCmd (void)
904 {
905 	if (cls.signon == SIGNONS)
906 	{
907 		//basic keyboard looking
908 		CL_AdjustAngles ();
909 
910 		//accumulate movement from other devices
911 		IN_Move (&cl.pendingcmd);
912 	}
913 
914 	cl.pendingcmd.seconds		= cl.mtime[0] - cl.pendingcmd.servertime;
915 }
916 
917 /*
918 =================
919 CL_SendCmd
920 =================
921 */
CL_SendCmd(void)922 void CL_SendCmd (void)
923 {
924 	usercmd_t		cmd;
925 
926 	if (cls.state != ca_connected)
927 		return;
928 
929 	// get basic movement from keyboard
930 	CL_BaseMove (&cmd);
931 
932 	// allow mice or other external controllers to add to the move
933 	cmd.forwardmove	+= cl.pendingcmd.forwardmove;
934 	cmd.sidemove	+= cl.pendingcmd.sidemove;
935 	cmd.upmove		+= cl.pendingcmd.upmove;
936 	cmd.sequence	= cl.movemessages;
937 	cmd.servertime	= cl.time;
938 	cmd.seconds		= cmd.servertime - cl.pendingcmd.servertime;
939 
940 	CL_FinishMove(&cmd);
941 
942 	if (cls.signon == SIGNONS)
943 		CL_SendMove (&cmd);	// send the unreliable message
944 	else
945 		CL_SendMove (NULL);
946 	memset(&cl.pendingcmd, 0, sizeof(cl.pendingcmd));
947 	cl.pendingcmd.servertime = cmd.servertime;
948 
949 	if (cls.demoplayback)
950 	{
951 		SZ_Clear (&cls.message);
952 		return;
953 	}
954 
955 // send the reliable message
956 	if (!cls.message.cursize)
957 		return;		// no message at all
958 
959 	if (!NET_CanSendMessage (cls.netcon))
960 	{
961 		Con_DPrintf ("CL_SendCmd: can't send\n");
962 		return;
963 	}
964 
965 	if (NET_SendMessage (cls.netcon, &cls.message) == -1)
966 		Host_Error ("CL_SendCmd: lost server connection");
967 
968 	SZ_Clear (&cls.message);
969 }
970 
971 /*
972 =============
973 CL_Tracepos_f -- johnfitz
974 
975 display impact point of trace along VPN
976 =============
977 */
CL_Tracepos_f(void)978 void CL_Tracepos_f (void)
979 {
980 	vec3_t	v, w;
981 
982 	if (cls.state != ca_connected)
983 		return;
984 
985 	VectorMA(r_refdef.vieworg, 8192.0, vpn, v);
986 	TraceLine(r_refdef.vieworg, v, w);
987 
988 	if (VectorLength(w) == 0)
989 		Con_Printf ("Tracepos: trace didn't hit anything\n");
990 	else
991 		Con_Printf ("Tracepos: (%i %i %i)\n", (int)w[0], (int)w[1], (int)w[2]);
992 }
993 
994 /*
995 =============
996 CL_Viewpos_f -- johnfitz
997 
998 display client's position and angles
999 =============
1000 */
CL_Viewpos_f(void)1001 void CL_Viewpos_f (void)
1002 {
1003 	if (cls.state != ca_connected)
1004 		return;
1005 #if 0
1006 	//camera position
1007 	Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n",
1008 		(int)r_refdef.vieworg[0],
1009 		(int)r_refdef.vieworg[1],
1010 		(int)r_refdef.vieworg[2],
1011 		(int)r_refdef.viewangles[PITCH],
1012 		(int)r_refdef.viewangles[YAW],
1013 		(int)r_refdef.viewangles[ROLL]);
1014 #else
1015 	//player position
1016 	Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n",
1017 		(int)cl.entities[cl.viewentity].origin[0],
1018 		(int)cl.entities[cl.viewentity].origin[1],
1019 		(int)cl.entities[cl.viewentity].origin[2],
1020 		(int)cl.viewangles[PITCH],
1021 		(int)cl.viewangles[YAW],
1022 		(int)cl.viewangles[ROLL]);
1023 #endif
1024 }
1025 
CL_ServerExtension_FullServerinfo_f(void)1026 static void CL_ServerExtension_FullServerinfo_f(void)
1027 {
1028 	const char *newserverinfo = Cmd_Argv(1);
1029 	Q_strncpy(cl.serverinfo, newserverinfo, sizeof(cl.serverinfo));	//just replace it
1030 }
CL_ServerExtension_ServerinfoUpdate_f(void)1031 static void CL_ServerExtension_ServerinfoUpdate_f(void)
1032 {
1033 	const char *newserverkey = Cmd_Argv(1);
1034 	const char *newservervalue = Cmd_Argv(2);
1035 	Info_SetKey(cl.serverinfo, sizeof(cl.serverinfo), newserverkey, newservervalue);
1036 }
1037 
1038 /*
1039 =================
1040 CL_Init
1041 =================
1042 */
CL_Init(void)1043 void CL_Init (void)
1044 {
1045 	SZ_Alloc (&cls.message, 1024);
1046 
1047 	CL_InitInput ();
1048 	CL_InitTEnts ();
1049 
1050 	Cvar_RegisterVariable (&cl_name);
1051 	Cvar_RegisterVariable (&cl_color);
1052 	Cvar_RegisterVariable (&cl_upspeed);
1053 	Cvar_RegisterVariable (&cl_forwardspeed);
1054 	Cvar_RegisterVariable (&cl_backspeed);
1055 	Cvar_RegisterVariable (&cl_sidespeed);
1056 	Cvar_RegisterVariable (&cl_movespeedkey);
1057 	Cvar_RegisterVariable (&cl_yawspeed);
1058 	Cvar_RegisterVariable (&cl_pitchspeed);
1059 	Cvar_RegisterVariable (&cl_anglespeedkey);
1060 	Cvar_RegisterVariable (&cl_shownet);
1061 	Cvar_RegisterVariable (&cl_nolerp);
1062 	Cvar_RegisterVariable (&lookspring);
1063 	Cvar_RegisterVariable (&lookstrafe);
1064 	Cvar_RegisterVariable (&sensitivity);
1065 
1066 	Cvar_RegisterVariable (&cl_alwaysrun);
1067 
1068 	Cvar_RegisterVariable (&m_pitch);
1069 	Cvar_RegisterVariable (&m_yaw);
1070 	Cvar_RegisterVariable (&m_forward);
1071 	Cvar_RegisterVariable (&m_side);
1072 
1073 	Cvar_RegisterVariable (&cfg_unbindall);
1074 
1075 	Cvar_RegisterVariable (&cl_maxpitch); //johnfitz -- variable pitch clamping
1076 	Cvar_RegisterVariable (&cl_minpitch); //johnfitz -- variable pitch clamping
1077 
1078 	Cmd_AddCommand ("entities", CL_PrintEntities_f);
1079 	Cmd_AddCommand ("disconnect", CL_Disconnect_f);
1080 	Cmd_AddCommand ("record", CL_Record_f);
1081 	Cmd_AddCommand ("stop", CL_Stop_f);
1082 	Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
1083 	Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
1084 
1085 	Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz
1086 	Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz
1087 
1088 	//spike -- serverinfo stuff
1089 	Cmd_AddCommand_ServerCommand ("fullserverinfo", CL_ServerExtension_FullServerinfo_f);
1090 	Cmd_AddCommand_ServerCommand ("svi", CL_ServerExtension_ServerinfoUpdate_f);
1091 }
1092 
1093