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