]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_main.c
Too many fixes to mention. (sys_ticrate now controls packet rates, and other stuff)
[xonotic/darkplaces.git] / cl_main.c
1 /*
2 Copyright (C) 1996-1997 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_main.c  -- client main loop
21
22 #include "quakedef.h"
23
24 // we need to declare some mouse variables here, because the menu system
25 // references them even when on a unix system.
26
27 // these two are not intended to be set directly
28 cvar_t  cl_name = {"_cl_name", "player", true};
29 cvar_t  cl_color = {"_cl_color", "0", true};
30
31 cvar_t  cl_shownet = {"cl_shownet","0"};        // can be 0, 1, or 2
32 cvar_t  cl_nolerp = {"cl_nolerp","0"};
33
34 cvar_t  lookspring = {"lookspring","0", true};
35 cvar_t  lookstrafe = {"lookstrafe","0", true};
36 cvar_t  sensitivity = {"sensitivity","3", true};
37
38 cvar_t  m_pitch = {"m_pitch","0.022", true};
39 cvar_t  m_yaw = {"m_yaw","0.022", true};
40 cvar_t  m_forward = {"m_forward","1", true};
41 cvar_t  m_side = {"m_side","0.8", true};
42
43
44 client_static_t cls;
45 client_state_t  cl;
46 // FIXME: put these on hunk?
47 efrag_t                 cl_efrags[MAX_EFRAGS];
48 entity_t                cl_entities[MAX_EDICTS];
49 entity_t                cl_static_entities[MAX_STATIC_ENTITIES];
50 lightstyle_t    cl_lightstyle[MAX_LIGHTSTYLES];
51 dlight_t                cl_dlights[MAX_DLIGHTS];
52
53 int                             cl_numvisedicts;
54 entity_t                *cl_visedicts[MAX_VISEDICTS];
55
56 /*
57 =====================
58 CL_ClearState
59
60 =====================
61 */
62 void CL_ClearState (void)
63 {
64         int                     i;
65
66         if (!sv.active)
67                 Host_ClearMemory ();
68
69 // wipe the entire cl structure
70         memset (&cl, 0, sizeof(cl));
71
72         SZ_Clear (&cls.message);
73
74 // clear other arrays   
75         memset (cl_efrags, 0, sizeof(cl_efrags));
76         memset (cl_entities, 0, sizeof(cl_entities));
77         memset (cl_dlights, 0, sizeof(cl_dlights));
78         memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
79         memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
80         memset (cl_beams, 0, sizeof(cl_beams));
81         // LordHavoc: have to set up the baseline info for alpha and other stuff
82         for (i = 0;i < MAX_EDICTS;i++)
83         {
84                 cl_entities[i].baseline.alpha = 255;
85                 cl_entities[i].baseline.scale = 16;
86                 cl_entities[i].baseline.glowsize = 0;
87                 cl_entities[i].baseline.glowcolor = 254;
88                 cl_entities[i].baseline.colormod = 255;
89         }
90
91 //
92 // allocate the efrags and chain together into a free list
93 //
94         cl.free_efrags = cl_efrags;
95         for (i=0 ; i<MAX_EFRAGS-1 ; i++)
96                 cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
97         cl.free_efrags[i].entnext = NULL;
98 }
99
100 /*
101 =====================
102 CL_Disconnect
103
104 Sends a disconnect message to the server
105 This is also called on Host_Error, so it shouldn't cause any errors
106 =====================
107 */
108 void CL_Disconnect (void)
109 {
110 // stop sounds (especially looping!)
111         S_StopAllSounds (true);
112         
113 // bring the console down and fade the colors back to normal
114 //      SCR_BringDownConsole ();
115
116 // if running a local server, shut it down
117         if (cls.demoplayback)
118                 CL_StopPlayback ();
119         else if (cls.state == ca_connected)
120         {
121                 if (cls.demorecording)
122                         CL_Stop_f ();
123
124                 Con_DPrintf ("Sending clc_disconnect\n");
125                 SZ_Clear (&cls.message);
126                 MSG_WriteByte (&cls.message, clc_disconnect);
127                 NET_SendUnreliableMessage (cls.netcon, &cls.message);
128                 SZ_Clear (&cls.message);
129                 NET_Close (cls.netcon);
130
131                 cls.state = ca_disconnected;
132                 if (sv.active)
133                         Host_ShutdownServer(false);
134         }
135
136         cls.demoplayback = cls.timedemo = false;
137         cls.signon = 0;
138 }
139
140 void CL_Disconnect_f (void)
141 {
142         CL_Disconnect ();
143         if (sv.active)
144                 Host_ShutdownServer (false);
145 }
146
147
148
149
150 /*
151 =====================
152 CL_EstablishConnection
153
154 Host should be either "local" or a net address to be passed on
155 =====================
156 */
157 void CL_EstablishConnection (char *host)
158 {
159         if (cls.state == ca_dedicated)
160                 return;
161
162         if (cls.demoplayback)
163                 return;
164
165         CL_Disconnect ();
166
167         cls.netcon = NET_Connect (host);
168         if (!cls.netcon)
169                 Host_Error ("CL_Connect: connect failed\n");
170         Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
171         
172         cls.demonum = -1;                       // not in the demo loop now
173         cls.state = ca_connected;
174         cls.signon = 0;                         // need all the signon messages before playing
175 }
176
177 extern int numgltextures;
178 extern int texels;
179
180 /*
181 =====================
182 CL_SignonReply
183
184 An svc_signonnum has been received, perform a client side setup
185 =====================
186 */
187 void CL_SignonReply (void)
188 {
189         char    str[8192];
190
191 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
192
193         switch (cls.signon)
194         {
195         case 1:
196                 MSG_WriteByte (&cls.message, clc_stringcmd);
197                 MSG_WriteString (&cls.message, "prespawn");
198                 break;
199                 
200         case 2:         
201                 MSG_WriteByte (&cls.message, clc_stringcmd);
202                 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
203         
204                 MSG_WriteByte (&cls.message, clc_stringcmd);
205                 MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
206         
207                 MSG_WriteByte (&cls.message, clc_stringcmd);
208                 sprintf (str, "spawn %s", cls.spawnparms);
209                 MSG_WriteString (&cls.message, str);
210                 break;
211                 
212         case 3: 
213                 MSG_WriteByte (&cls.message, clc_stringcmd);
214                 MSG_WriteString (&cls.message, "begin");
215                 Cache_Report ();                // print remaining memory
216                 break;
217                 
218         case 4:
219                 SCR_EndLoadingPlaque ();                // allow normal screen updates
220                 // LordHavoc: debugging purposes
221                 Con_DPrintf("GLQuake texture slots in use: %i : %i : %i texels\n", texture_extension_number, numgltextures, texels);
222                 break;
223         }
224 }
225
226 /*
227 =====================
228 CL_NextDemo
229
230 Called to play the next demo in the demo loop
231 =====================
232 */
233 void CL_NextDemo (void)
234 {
235         char    str[1024];
236
237         if (cls.demonum == -1)
238                 return;         // don't play demos
239
240         SCR_BeginLoadingPlaque ();
241
242         if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
243         {
244                 cls.demonum = 0;
245                 if (!cls.demos[cls.demonum][0])
246                 {
247                         Con_Printf ("No demos listed with startdemos\n");
248                         cls.demonum = -1;
249                         return;
250                 }
251         }
252
253         sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
254         Cbuf_InsertText (str);
255         cls.demonum++;
256 }
257
258 /*
259 ==============
260 CL_PrintEntities_f
261 ==============
262 */
263 void CL_PrintEntities_f (void)
264 {
265         entity_t        *ent;
266         int                     i;
267         
268         for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
269         {
270                 Con_Printf ("%3i:",i);
271                 if (!ent->model)
272                 {
273                         Con_Printf ("EMPTY\n");
274                         continue;
275                 }
276                 Con_Printf ("%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
277                 ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
278         }
279 }
280
281
282 /*
283 ===============
284 SetPal
285
286 Debugging tool, just flashes the screen
287 ===============
288 */
289 void SetPal (int i)
290 {
291 #if 0
292         static int old;
293         byte    pal[768];
294         int             c;
295         
296         if (i == old)
297                 return;
298         old = i;
299
300         if (i==0)
301                 VID_SetPalette (host_basepal);
302         else if (i==1)
303         {
304                 for (c=0 ; c<768 ; c+=3)
305                 {
306                         pal[c] = 0;
307                         pal[c+1] = 255;
308                         pal[c+2] = 0;
309                 }
310                 VID_SetPalette (pal);
311         }
312         else
313         {
314                 for (c=0 ; c<768 ; c+=3)
315                 {
316                         pal[c] = 0;
317                         pal[c+1] = 0;
318                         pal[c+2] = 255;
319                 }
320                 VID_SetPalette (pal);
321         }
322 #endif
323 }
324
325 /*
326 ===============
327 CL_AllocDlight
328
329 ===============
330 */
331 dlight_t *CL_AllocDlight (int key)
332 {
333         int             i;
334         dlight_t        *dl;
335
336 // first look for an exact key match
337         if (key)
338         {
339                 dl = cl_dlights;
340                 for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
341                 {
342                         if (dl->key == key)
343                         {
344                                 memset (dl, 0, sizeof(*dl));
345                                 dl->key = key;
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                         return dl;
360                 }
361         }
362
363         dl = &cl_dlights[0];
364         memset (dl, 0, sizeof(*dl));
365         dl->key = key;
366         return dl;
367 }
368
369
370 /*
371 ===============
372 CL_DecayLights
373
374 ===============
375 */
376 void CL_DecayLights (void)
377 {
378         int                     i;
379         dlight_t        *dl;
380         float           time;
381         
382         time = cl.time - cl.oldtime;
383
384         dl = cl_dlights;
385         for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
386         {
387                 if (dl->die < cl.time || !dl->radius)
388                         continue;
389                 
390                 dl->radius -= time*dl->decay;
391                 if (dl->radius < 0)
392                         dl->radius = 0;
393         }
394 }
395
396
397 /*
398 ===============
399 CL_LerpPoint
400
401 Determines the fraction between the last two messages that the objects
402 should be put at.
403 ===============
404 */
405 float   CL_LerpPoint (void)
406 {
407         float   f, frac;
408
409         f = cl.mtime[0] - cl.mtime[1];
410         
411         if (!f || cl_nolerp.value || cls.timedemo || sv.active)
412         {
413                 cl.time = cl.mtime[0];
414                 return 1;
415         }
416                 
417         if (f > 0.1)
418         {       // dropped packet, or start of demo
419                 cl.mtime[1] = cl.mtime[0] - 0.1;
420                 f = 0.1;
421         }
422         frac = (cl.time - cl.mtime[1]) / f;
423 //Con_Printf ("frac: %f\n",frac);
424         if (frac < 0)
425         {
426                 if (frac < -0.01)
427                 {
428 SetPal(1);
429                         cl.time = cl.mtime[1];
430 //                              Con_Printf ("low frac\n");
431                 }
432                 frac = 0;
433         }
434         else if (frac > 1)
435         {
436                 if (frac > 1.01)
437                 {
438 SetPal(2);
439                         cl.time = cl.mtime[0];
440 //                              Con_Printf ("high frac\n");
441                 }
442                 frac = 1;
443         }
444         else
445                 SetPal(0);
446                 
447         return frac;
448 }
449
450
451 /*
452 ===============
453 CL_RelinkEntities
454 ===============
455 */
456 void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent);
457 void CL_RelinkEntities (void)
458 {
459         entity_t        *ent;
460         int                     i, j;
461         float           frac, f, d;
462         vec3_t          delta;
463         float           bobjrotate;
464         vec3_t          oldorg;
465         dlight_t        *dl;
466         byte            *tempcolor;
467
468 // determine partial update time        
469         frac = CL_LerpPoint ();
470
471         cl_numvisedicts = 0;
472
473 //
474 // interpolate player info
475 //
476         for (i=0 ; i<3 ; i++)
477                 cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
478
479         if (cls.demoplayback)
480         {
481         // interpolate the angles       
482                 for (j=0 ; j<3 ; j++)
483                 {
484                         d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
485                         if (d > 180)
486                                 d -= 360;
487                         else if (d < -180)
488                                 d += 360;
489                         cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;
490                 }
491         }
492         
493         bobjrotate = anglemod(100*cl.time);
494         
495 // start on the entity after the world
496         for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)
497         {
498                 if (!ent->model)
499                 {       // empty slot
500                         if (ent->forcelink)
501                                 R_RemoveEfrags (ent);   // just became empty
502                         continue;
503                 }
504
505 // if the object wasn't included in the last packet, remove it
506                 if (ent->msgtime != cl.mtime[0])
507                 {
508                         ent->model = NULL;
509                         continue;
510                 }
511
512                 VectorCopy (ent->origin, oldorg);
513
514                 if (ent->forcelink)
515                 {       // the entity was not updated in the last message
516                         // so move to the final spot
517                         VectorCopy (ent->msg_origins[0], ent->origin);
518                         VectorCopy (ent->msg_angles[0], ent->angles);
519                 }
520                 else
521                 {       // if the delta is large, assume a teleport and don't lerp
522                         f = frac;
523                         for (j=0 ; j<3 ; j++)
524                         {
525                                 delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
526                                 // LordHavoc: increased lerp tolerance from 100 to 200
527                                 if (delta[j] > 200 || delta[j] < -200)
528                                         f = 1;          // assume a teleportation, not a motion
529                         }
530
531                 // interpolate the origin and angles
532                         for (j=0 ; j<3 ; j++)
533                         {
534                                 ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
535
536                                 d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
537                                 if (d > 180)
538                                         d -= 360;
539                                 else if (d < -180)
540                                         d += 360;
541                                 ent->angles[j] = ent->msg_angles[1][j] + f*d;
542                         }
543                         
544                 }
545
546                 if (ent->effects & EF_BRIGHTFIELD)
547                         R_EntityParticles (ent);
548                 if (ent->effects & EF_MUZZLEFLASH)
549                 {
550                         vec3_t          fv, rv, uv;
551
552                         dl = CL_AllocDlight (i);
553                         VectorCopy (ent->origin,  dl->origin);
554                         dl->origin[2] += 16;
555                         AngleVectors (ent->angles, fv, rv, uv);
556                          
557                         VectorMA (dl->origin, 18, fv, dl->origin);
558                         dl->radius = 200 + (rand()&31);
559                         dl->minlight = 32;
560                         dl->die = cl.time + 0.1;
561                         dl->color[0] = 1.0;dl->color[1] = 1.0;dl->color[2] = 1.0;
562                 }
563                 if (ent->effects & EF_BRIGHTLIGHT)
564                 {                       
565                         dl = CL_AllocDlight (i);
566                         VectorCopy (ent->origin,  dl->origin);
567                         dl->origin[2] += 16;
568                         dl->radius = 400 + (rand()&31);
569                         dl->die = cl.time + 0.001;
570                         dl->color[0] = 1.0;dl->color[1] = 1.0;dl->color[2] = 1.0;
571                 }
572                 if (ent->effects & EF_DIMLIGHT)
573                 {                       
574                         dl = CL_AllocDlight (i);
575                         VectorCopy (ent->origin,  dl->origin);
576                         dl->radius = 200 + (rand()&31);
577                         dl->die = cl.time + 0.001;
578                         dl->color[0] = 1.0;dl->color[1] = 1.0;dl->color[2] = 1.0;
579                 }
580                 // LordHavoc: added EF_RED and EF_BLUE
581                 if (ent->effects & EF_RED) // red
582                 {                       
583                         if (ent->effects & EF_BLUE) // magenta
584                         {
585                                 dl = CL_AllocDlight (i);
586                                 VectorCopy (ent->origin,  dl->origin);
587                                 dl->radius = 200 + (rand()&31);
588                                 dl->die = cl.time + 0.001;
589                                 dl->color[0] = 0.7;dl->color[1] = 0.07;dl->color[2] = 0.7;
590                         }
591                         else // red
592                         {
593                                 dl = CL_AllocDlight (i);
594                                 VectorCopy (ent->origin,  dl->origin);
595                                 dl->radius = 200 + (rand()&31);
596                                 dl->die = cl.time + 0.001;
597                                 dl->color[0] = 0.8;dl->color[1] = 0.05;dl->color[2] = 0.05;
598                         }
599                 }
600                 else if (ent->effects & EF_BLUE) // blue
601                 {
602                         dl = CL_AllocDlight (i);
603                         VectorCopy (ent->origin,  dl->origin);
604                         dl->radius = 200 + (rand()&31);
605                         dl->die = cl.time + 0.001;
606                         dl->color[0] = 0.05;dl->color[1] = 0.05;dl->color[2] = 0.8;
607                 }
608
609                 if (ent->model->flags) // LordHavoc: if the model has no flags, don't check each
610                 {
611                 // rotate binary objects locally
612                         if (ent->model->flags & EF_ROTATE)
613                                 ent->angles[1] = bobjrotate;
614                         if (ent->model->flags & EF_GIB)
615                                 R_RocketTrail (oldorg, ent->origin, 2, ent);
616                         else if (ent->model->flags & EF_ZOMGIB)
617                                 R_RocketTrail (oldorg, ent->origin, 4, ent);
618                         else if (ent->model->flags & EF_TRACER)
619                                 R_RocketTrail (oldorg, ent->origin, 3, ent);
620                         else if (ent->model->flags & EF_TRACER2)
621                                 R_RocketTrail (oldorg, ent->origin, 5, ent);
622                         else if (ent->model->flags & EF_ROCKET)
623                         {
624                                 R_RocketTrail (oldorg, ent->origin, 0, ent);
625                                 dl = CL_AllocDlight (i);
626                                 VectorCopy (ent->origin, dl->origin);
627                                 dl->radius = 200;
628                                 dl->die = cl.time + 0.001;
629                                 dl->color[0] = 1.0;dl->color[1] = 0.8;dl->color[2] = 0.4;
630                         }
631                         else if (ent->model->flags & EF_GRENADE)
632                         {
633                                 if (ent->alpha == -1) // LordHavoc: Nehahra dem compatibility
634                                         R_RocketTrail (oldorg, ent->origin, 7, ent);
635                                 else
636                                         R_RocketTrail (oldorg, ent->origin, 1, ent);
637                         }
638                         else if (ent->model->flags & EF_TRACER3)
639                                 R_RocketTrail (oldorg, ent->origin, 6, ent);
640                 }
641                 if (ent->glowsize) // LordHavoc: customizable glow
642                 {
643                         dl = CL_AllocDlight (i);
644                         VectorCopy (ent->origin, dl->origin);
645                         dl->dark = ent->glowsize < 0; // darklight
646                         dl->radius = ent->glowsize;
647                         if (dl->dark)
648                         {
649                                 if (ent->glowtrail) // LordHavoc: all darklights leave black trails
650                                         R_RocketTrail2 (oldorg, ent->origin, 0, ent);
651                                 dl->radius = -ent->glowsize;
652                         }
653                         else if (ent->glowtrail) // LordHavoc: customizable glow and trail
654                                 R_RocketTrail2 (oldorg, ent->origin, ent->glowcolor, ent);
655                         dl->die = cl.time + 0.001;
656                         tempcolor = (byte *)&d_8to24table[ent->glowcolor];
657                         dl->color[0] = tempcolor[0]*(1.0/255.0);dl->color[1] = tempcolor[1]*(1.0/255.0);dl->color[2] = tempcolor[2]*(1.0/255.0);
658                 }
659                 else if (ent->glowtrail) // LordHavoc: customizable glow and trail
660                         R_RocketTrail2 (oldorg, ent->origin, ent->glowcolor, ent);
661
662                 ent->forcelink = false;
663
664                 if (i == cl.viewentity && !chase_active.value)
665                         continue;
666
667 // LordHavoc: enabled EF_NODRAW
668                 if (!ent->model || ent->effects & EF_NODRAW)
669                         continue;
670                 if (cl_numvisedicts < MAX_VISEDICTS)
671                 {
672                         cl_visedicts[cl_numvisedicts] = ent;
673                         cl_numvisedicts++;
674                 }
675         }
676
677 }
678
679
680 /*
681 ===============
682 CL_ReadFromServer
683
684 Read all incoming data from the server
685 ===============
686 */
687 int CL_ReadFromServer (void)
688 {
689         int             ret;
690
691         cl.oldtime = cl.time;
692         cl.time += host_frametime;
693         
694         do
695         {
696                 ret = CL_GetMessage ();
697                 if (ret == -1)
698                         Host_Error ("CL_ReadFromServer: lost server connection");
699                 if (!ret)
700                         break;
701                 
702                 cl.last_received_message = realtime;
703                 CL_ParseServerMessage ();
704         } while (ret && cls.state == ca_connected);
705         
706         if (cl_shownet.value)
707                 Con_Printf ("\n");
708
709         CL_RelinkEntities ();
710         CL_UpdateTEnts ();
711
712 //
713 // bring the links up to date
714 //
715         return 0;
716 }
717
718 /*
719 =================
720 CL_SendCmd
721 =================
722 */
723 void CL_SendCmd (void)
724 {
725         usercmd_t               cmd;
726
727         if (cls.state != ca_connected)
728                 return;
729
730         if (cls.signon == SIGNONS)
731         {
732         // get basic movement from keyboard
733                 CL_BaseMove (&cmd);
734         
735         // allow mice or other external controllers to add to the move
736                 IN_Move (&cmd);
737         
738         // send the unreliable message
739                 CL_SendMove (&cmd);
740         
741         }
742
743         if (cls.demoplayback)
744         {
745                 SZ_Clear (&cls.message);
746                 return;
747         }
748         
749 // send the reliable message
750         if (!cls.message.cursize)
751                 return;         // no message at all
752         
753         if (!NET_CanSendMessage (cls.netcon))
754         {
755                 Con_DPrintf ("CL_WriteToServer: can't send\n");
756                 return;
757         }
758
759         if (NET_SendMessage (cls.netcon, &cls.message) == -1)
760                 Host_Error ("CL_WriteToServer: lost server connection");
761
762         SZ_Clear (&cls.message);
763 }
764
765 // LordHavoc: pausedemo command
766 void CL_PauseDemo_f (void)
767 {
768         cls.demopaused = !cls.demopaused;
769         if (cls.demopaused)
770                 Con_Printf("Demo paused\n");
771         else
772                 Con_Printf("Demo unpaused\n");
773 }
774
775 cvar_t demo_nehahra = {"demo_nehahra", "0"};
776
777 /*
778 =================
779 CL_Init
780 =================
781 */
782 void CL_Init (void)
783 {       
784         SZ_Alloc (&cls.message, 1024);
785
786         CL_InitInput ();
787         CL_InitTEnts ();
788         
789 //
790 // register our commands
791 //
792         Cvar_RegisterVariable (&cl_name);
793         Cvar_RegisterVariable (&cl_color);
794         Cvar_RegisterVariable (&cl_upspeed);
795         Cvar_RegisterVariable (&cl_forwardspeed);
796         Cvar_RegisterVariable (&cl_backspeed);
797         Cvar_RegisterVariable (&cl_sidespeed);
798         Cvar_RegisterVariable (&cl_movespeedkey);
799         Cvar_RegisterVariable (&cl_yawspeed);
800         Cvar_RegisterVariable (&cl_pitchspeed);
801         Cvar_RegisterVariable (&cl_anglespeedkey);
802         Cvar_RegisterVariable (&cl_shownet);
803         Cvar_RegisterVariable (&cl_nolerp);
804         Cvar_RegisterVariable (&lookspring);
805         Cvar_RegisterVariable (&lookstrafe);
806         Cvar_RegisterVariable (&sensitivity);
807
808         Cvar_RegisterVariable (&m_pitch);
809         Cvar_RegisterVariable (&m_yaw);
810         Cvar_RegisterVariable (&m_forward);
811         Cvar_RegisterVariable (&m_side);
812
813 //      Cvar_RegisterVariable (&cl_autofire);
814         
815         Cmd_AddCommand ("entities", CL_PrintEntities_f);
816         Cmd_AddCommand ("disconnect", CL_Disconnect_f);
817         Cmd_AddCommand ("record", CL_Record_f);
818         Cmd_AddCommand ("stop", CL_Stop_f);
819         Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
820         Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
821
822         // LordHavoc: added pausedemo
823         Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
824         // LordHavoc: added demo_nehahra cvar
825         Cvar_RegisterVariable (&demo_nehahra);
826         if (nehahra)
827                 Cvar_SetValue("demo_nehahra", 1);
828 }
829