pmodel fixes (now works properly in listen/singleplayer)
[xonotic/darkplaces.git] / host_cmd.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
21 #include "quakedef.h"
22
23 extern cvar_t   pausable;
24
25 int     current_skill;
26
27 void Mod_Print (void);
28
29 /*
30 ==================
31 Host_Quit_f
32 ==================
33 */
34
35 extern void M_Menu_Quit_f (void);
36
37 void Host_Quit_f (void)
38 {
39         if (key_dest != key_console && cls.state != ca_dedicated)
40         {
41                 M_Menu_Quit_f ();
42                 return;
43         }
44         CL_Disconnect ();
45         Host_ShutdownServer(false);             
46
47         Sys_Quit ();
48 }
49
50
51 /*
52 ==================
53 Host_Status_f
54 ==================
55 */
56 void Host_Status_f (void)
57 {
58         client_t        *client;
59         int                     seconds;
60         int                     minutes;
61         int                     hours = 0;
62         int                     j;
63         void            (*print) (char *fmt, ...);
64         
65         if (cmd_source == src_command)
66         {
67                 if (!sv.active)
68                 {
69                         Cmd_ForwardToServer ();
70                         return;
71                 }
72                 print = Con_Printf;
73         }
74         else
75                 print = SV_ClientPrintf;
76
77         print ("host:    %s\n", Cvar_VariableString ("hostname"));
78         print ("version: %4.2f\n", VERSION);
79         if (tcpipAvailable)
80                 print ("tcp/ip:  %s\n", my_tcpip_address);
81         if (ipxAvailable)
82                 print ("ipx:     %s\n", my_ipx_address);
83         print ("map:     %s\n", sv.name);
84         print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
85         for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
86         {
87                 if (!client->active)
88                         continue;
89                 seconds = (int)(net_time - client->netconnection->connecttime);
90                 minutes = seconds / 60;
91                 if (minutes)
92                 {
93                         seconds -= (minutes * 60);
94                         hours = minutes / 60;
95                         if (hours)
96                                 minutes -= (hours * 60);
97                 }
98                 else
99                         hours = 0;
100                 print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
101                 print ("   %s\n", client->netconnection->address);
102         }
103 }
104
105
106 /*
107 ==================
108 Host_God_f
109
110 Sets client to godmode
111 ==================
112 */
113 void Host_God_f (void)
114 {
115         if (cmd_source == src_command)
116         {
117                 Cmd_ForwardToServer ();
118                 return;
119         }
120
121         if (pr_global_struct->deathmatch && !host_client->privileged)
122                 return;
123
124         sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
125         if (!((int)sv_player->v.flags & FL_GODMODE) )
126                 SV_ClientPrintf ("godmode OFF\n");
127         else
128                 SV_ClientPrintf ("godmode ON\n");
129 }
130
131 void Host_Notarget_f (void)
132 {
133         if (cmd_source == src_command)
134         {
135                 Cmd_ForwardToServer ();
136                 return;
137         }
138
139         if (pr_global_struct->deathmatch && !host_client->privileged)
140                 return;
141
142         sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;
143         if (!((int)sv_player->v.flags & FL_NOTARGET) )
144                 SV_ClientPrintf ("notarget OFF\n");
145         else
146                 SV_ClientPrintf ("notarget ON\n");
147 }
148
149 qboolean noclip_anglehack;
150
151 void Host_Noclip_f (void)
152 {
153         if (cmd_source == src_command)
154         {
155                 Cmd_ForwardToServer ();
156                 return;
157         }
158
159         if (pr_global_struct->deathmatch && !host_client->privileged)
160                 return;
161
162         if (sv_player->v.movetype != MOVETYPE_NOCLIP)
163         {
164                 noclip_anglehack = true;
165                 sv_player->v.movetype = MOVETYPE_NOCLIP;
166                 SV_ClientPrintf ("noclip ON\n");
167         }
168         else
169         {
170                 noclip_anglehack = false;
171                 sv_player->v.movetype = MOVETYPE_WALK;
172                 SV_ClientPrintf ("noclip OFF\n");
173         }
174 }
175
176 /*
177 ==================
178 Host_Fly_f
179
180 Sets client to flymode
181 ==================
182 */
183 void Host_Fly_f (void)
184 {
185         if (cmd_source == src_command)
186         {
187                 Cmd_ForwardToServer ();
188                 return;
189         }
190
191         if (pr_global_struct->deathmatch && !host_client->privileged)
192                 return;
193
194         if (sv_player->v.movetype != MOVETYPE_FLY)
195         {
196                 sv_player->v.movetype = MOVETYPE_FLY;
197                 SV_ClientPrintf ("flymode ON\n");
198         }
199         else
200         {
201                 sv_player->v.movetype = MOVETYPE_WALK;
202                 SV_ClientPrintf ("flymode OFF\n");
203         }
204 }
205
206
207 /*
208 ==================
209 Host_Ping_f
210
211 ==================
212 */
213 void Host_Ping_f (void)
214 {
215         int             i, j;
216         float   total;
217         client_t        *client;
218         
219         if (cmd_source == src_command)
220         {
221                 Cmd_ForwardToServer ();
222                 return;
223         }
224
225         SV_ClientPrintf ("Client ping times:\n");
226         for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
227         {
228                 if (!client->active)
229                         continue;
230                 total = 0;
231                 for (j=0 ; j<NUM_PING_TIMES ; j++)
232                         total+=client->ping_times[j];
233                 total /= NUM_PING_TIMES;
234                 SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name);
235         }
236 }
237
238 /*
239 ===============================================================================
240
241 SERVER TRANSITIONS
242
243 ===============================================================================
244 */
245
246
247 /*
248 ======================
249 Host_Map_f
250
251 handle a 
252 map <servername>
253 command from the console.  Active clients are kicked off.
254 ======================
255 */
256 void Host_Map_f (void)
257 {
258         int             i;
259         char    name[MAX_QPATH];
260
261         if (cmd_source != src_command)
262                 return;
263
264         cls.demonum = -1;               // stop demo loop in case this fails
265
266         CL_Disconnect ();
267         Host_ShutdownServer(false);             
268
269         key_dest = key_game;                    // remove console or menu
270         SCR_BeginLoadingPlaque ();
271
272         cls.mapstring[0] = 0;
273         for (i=0 ; i<Cmd_Argc() ; i++)
274         {
275                 strcat (cls.mapstring, Cmd_Argv(i));
276                 strcat (cls.mapstring, " ");
277         }
278         strcat (cls.mapstring, "\n");
279
280         svs.serverflags = 0;                    // haven't completed an episode yet
281         strcpy (name, Cmd_Argv(1));
282         SV_SpawnServer (name);
283         if (!sv.active)
284                 return;
285         
286         if (cls.state != ca_dedicated)
287         {
288                 strcpy (cls.spawnparms, "");
289
290                 for (i=2 ; i<Cmd_Argc() ; i++)
291                 {
292                         strcat (cls.spawnparms, Cmd_Argv(i));
293                         strcat (cls.spawnparms, " ");
294                 }
295                 
296                 Cmd_ExecuteString ("connect local", src_command);
297         }       
298 }
299
300 /*
301 ==================
302 Host_Changelevel_f
303
304 Goes to a new map, taking all clients along
305 ==================
306 */
307 void Host_Changelevel_f (void)
308 {
309         char    level[MAX_QPATH];
310
311         if (Cmd_Argc() != 2)
312         {
313                 Con_Printf ("changelevel <levelname> : continue game on a new level\n");
314                 return;
315         }
316         if (!sv.active || cls.demoplayback)
317         {
318                 Con_Printf ("Only the server may changelevel\n");
319                 return;
320         }
321         SV_SaveSpawnparms ();
322         strcpy (level, Cmd_Argv(1));
323         SV_SpawnServer (level);
324 }
325
326 /*
327 ==================
328 Host_Restart_f
329
330 Restarts the current server for a dead player
331 ==================
332 */
333 void Host_Restart_f (void)
334 {
335         char    mapname[MAX_QPATH];
336
337         if (cls.demoplayback || !sv.active)
338                 return;
339
340         if (cmd_source != src_command)
341                 return;
342         strcpy (mapname, sv.name);      // must copy out, because it gets cleared
343                                                                 // in sv_spawnserver
344         SV_SpawnServer (mapname);
345 }
346
347 /*
348 ==================
349 Host_Reconnect_f
350
351 This command causes the client to wait for the signon messages again.
352 This is sent just before a server changes levels
353 ==================
354 */
355 void Host_Reconnect_f (void)
356 {
357         SCR_BeginLoadingPlaque ();
358         cls.signon = 0;         // need new connection messages
359 }
360
361 /*
362 =====================
363 Host_Connect_f
364
365 User command to connect to server
366 =====================
367 */
368 void Host_Connect_f (void)
369 {
370         char    name[MAX_QPATH];
371         
372         cls.demonum = -1;               // stop demo loop in case this fails
373         if (cls.demoplayback)
374         {
375                 CL_StopPlayback ();
376                 CL_Disconnect ();
377         }
378         strcpy (name, Cmd_Argv(1));
379         CL_EstablishConnection (name);
380         Host_Reconnect_f ();
381 }
382
383
384 /*
385 ===============================================================================
386
387 LOAD / SAVE GAME
388
389 ===============================================================================
390 */
391
392 #define SAVEGAME_VERSION        5
393
394 /*
395 ===============
396 Host_SavegameComment
397
398 Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current 
399 ===============
400 */
401 void Host_SavegameComment (char *text)
402 {
403         int             i;
404         char    kills[20];
405
406         for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
407                 text[i] = ' ';
408         memcpy (text, cl.levelname, strlen(cl.levelname));
409         sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
410         memcpy (text+22, kills, strlen(kills));
411 // convert space to _ to make stdio happy
412         for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
413                 if (text[i] == ' ')
414                         text[i] = '_';
415         text[SAVEGAME_COMMENT_LENGTH] = '\0';
416 }
417
418
419 /*
420 ===============
421 Host_Savegame_f
422 ===============
423 */
424 void Host_Savegame_f (void)
425 {
426         char    name[256];
427         FILE    *f;
428         int             i;
429         char    comment[SAVEGAME_COMMENT_LENGTH+1];
430
431         if (cmd_source != src_command)
432                 return;
433
434         if (!sv.active)
435         {
436                 Con_Printf ("Not playing a local game.\n");
437                 return;
438         }
439
440         if (cl.intermission)
441         {
442                 Con_Printf ("Can't save in intermission.\n");
443                 return;
444         }
445
446         if (svs.maxclients != 1)
447         {
448                 Con_Printf ("Can't save multiplayer games.\n");
449                 return;
450         }
451
452         if (Cmd_Argc() != 2)
453         {
454                 Con_Printf ("save <savename> : save a game\n");
455                 return;
456         }
457
458         if (strstr(Cmd_Argv(1), ".."))
459         {
460                 Con_Printf ("Relative pathnames are not allowed.\n");
461                 return;
462         }
463                 
464         for (i=0 ; i<svs.maxclients ; i++)
465         {
466                 if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) )
467                 {
468                         Con_Printf ("Can't savegame with a dead player\n");
469                         return;
470                 }
471         }
472
473         sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
474         COM_DefaultExtension (name, ".sav");
475         
476         Con_Printf ("Saving game to %s...\n", name);
477         f = fopen (name, "w");
478         if (!f)
479         {
480                 Con_Printf ("ERROR: couldn't open.\n");
481                 return;
482         }
483         
484         fprintf (f, "%i\n", SAVEGAME_VERSION);
485         Host_SavegameComment (comment);
486         fprintf (f, "%s\n", comment);
487         for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
488                 fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
489         fprintf (f, "%d\n", current_skill);
490         fprintf (f, "%s\n", sv.name);
491         fprintf (f, "%f\n",sv.time);
492
493 // write the light styles
494
495         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
496         {
497                 if (sv.lightstyles[i])
498                         fprintf (f, "%s\n", sv.lightstyles[i]);
499                 else
500                         fprintf (f,"m\n");
501         }
502
503
504         ED_WriteGlobals (f);
505         for (i=0 ; i<sv.num_edicts ; i++)
506         {
507                 ED_Write (f, EDICT_NUM(i));
508                 fflush (f);
509         }
510         fclose (f);
511         Con_Printf ("done.\n");
512 }
513
514
515 /*
516 ===============
517 Host_Loadgame_f
518 ===============
519 */
520 void Host_Loadgame_f (void)
521 {
522         char    name[MAX_OSPATH];
523         FILE    *f;
524         char    mapname[MAX_QPATH];
525         float   time, tfloat;
526         char    str[32768], *start;
527         int             i, r;
528         edict_t *ent;
529         int             entnum;
530         int             version;
531         float                   spawn_parms[NUM_SPAWN_PARMS];
532
533         if (cmd_source != src_command)
534                 return;
535
536         if (Cmd_Argc() != 2)
537         {
538                 Con_Printf ("load <savename> : load a game\n");
539                 return;
540         }
541
542         cls.demonum = -1;               // stop demo loop in case this fails
543
544         sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
545         COM_DefaultExtension (name, ".sav");
546         
547 // we can't call SCR_BeginLoadingPlaque, because too much stack space has
548 // been used.  The menu calls it before stuffing loadgame command
549 //      SCR_BeginLoadingPlaque ();
550
551         Con_Printf ("Loading game from %s...\n", name);
552         f = fopen (name, "r");
553         if (!f)
554         {
555                 Con_Printf ("ERROR: couldn't open.\n");
556                 return;
557         }
558
559         fscanf (f, "%i\n", &version);
560         if (version != SAVEGAME_VERSION)
561         {
562                 fclose (f);
563                 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
564                 return;
565         }
566         fscanf (f, "%s\n", str);
567         for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
568                 fscanf (f, "%f\n", &spawn_parms[i]);
569 // this silliness is so we can load 1.06 save files, which have float skill values
570         fscanf (f, "%f\n", &tfloat);
571         current_skill = (int)(tfloat + 0.1);
572         Cvar_SetValue ("skill", (float)current_skill);
573
574         fscanf (f, "%s\n",mapname);
575         fscanf (f, "%f\n",&time);
576
577         CL_Disconnect_f ();
578         
579         SV_SpawnServer (mapname);
580         if (!sv.active)
581         {
582                 Con_Printf ("Couldn't load map\n");
583                 return;
584         }
585         sv.paused = true;               // pause until all clients connect
586         sv.loadgame = true;
587
588 // load the light styles
589
590         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
591         {
592                 fscanf (f, "%s\n", str);
593                 sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
594                 strcpy (sv.lightstyles[i], str);
595         }
596
597 // load the edicts out of the savegame file
598         entnum = -1;            // -1 is the globals
599         while (!feof(f))
600         {
601                 for (i=0 ; i<sizeof(str)-1 ; i++)
602                 {
603                         r = fgetc (f);
604                         if (r == EOF || !r)
605                                 break;
606                         str[i] = r;
607                         if (r == '}')
608                         {
609                                 i++;
610                                 break;
611                         }
612                 }
613                 if (i == sizeof(str)-1)
614                         Sys_Error ("Loadgame buffer overflow");
615                 str[i] = 0;
616                 start = str;
617                 start = COM_Parse(str);
618                 if (!com_token[0])
619                         break;          // end of file
620                 if (strcmp(com_token,"{"))
621                         Sys_Error ("First token isn't a brace");
622                         
623                 if (entnum == -1)
624                 {       // parse the global vars
625                         ED_ParseGlobals (start);
626                 }
627                 else
628                 {       // parse an edict
629
630                         ent = EDICT_NUM(entnum);
631                         memset (&ent->v, 0, progs->entityfields * 4);
632                         ent->free = false;
633                         ED_ParseEdict (start, ent);
634         
635                 // link it into the bsp tree
636                         if (!ent->free)
637                                 SV_LinkEdict (ent, false);
638                 }
639
640                 entnum++;
641         }
642         
643         sv.num_edicts = entnum;
644         sv.time = time;
645
646         fclose (f);
647
648         for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
649                 svs.clients->spawn_parms[i] = spawn_parms[i];
650
651         if (cls.state != ca_dedicated)
652         {
653                 CL_EstablishConnection ("local");
654                 Host_Reconnect_f ();
655         }
656 }
657
658 //============================================================================
659
660 /*
661 ======================
662 Host_Name_f
663 ======================
664 */
665 void Host_Name_f (void)
666 {
667         char    *newName;
668
669         if (Cmd_Argc () == 1)
670         {
671                 Con_Printf ("\"name\" is \"%s\"\n", cl_name.string);
672                 return;
673         }
674         if (Cmd_Argc () == 2)
675                 newName = Cmd_Argv(1);  
676         else
677                 newName = Cmd_Args();
678         newName[15] = 0;
679
680         if (cmd_source == src_command)
681         {
682                 if (strcmp(cl_name.string, newName) == 0)
683                         return;
684                 Cvar_Set ("_cl_name", newName);
685                 if (cls.state == ca_connected)
686                         Cmd_ForwardToServer ();
687                 return;
688         }
689
690         if (host_client->name[0] && strcmp(host_client->name, "unconnected") )
691                 if (strcmp(host_client->name, newName) != 0)
692                         Con_Printf ("%s renamed to %s\n", host_client->name, newName);
693         strcpy (host_client->name, newName);
694         host_client->edict->v.netname = host_client->name - pr_strings;
695         
696 // send notification to all clients
697         
698         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
699         MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
700         MSG_WriteString (&sv.reliable_datagram, host_client->name);
701 }
702
703         
704 void Host_Version_f (void)
705 {
706         Con_Printf ("Version %4.2f\n", VERSION);
707         Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
708 }
709
710 #ifdef IDGODS
711 void Host_Please_f (void)
712 {
713         client_t *cl;
714         int                     j;
715         
716         if (cmd_source != src_command)
717                 return;
718
719         if ((Cmd_Argc () == 3) && strcmp(Cmd_Argv(1), "#") == 0)
720         {
721                 j = atof(Cmd_Argv(2)) - 1;
722                 if (j < 0 || j >= svs.maxclients)
723                         return;
724                 if (!svs.clients[j].active)
725                         return;
726                 cl = &svs.clients[j];
727                 if (cl->privileged)
728                 {
729                         cl->privileged = false;
730                         cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
731                         cl->edict->v.movetype = MOVETYPE_WALK;
732                         noclip_anglehack = false;
733                 }
734                 else
735                         cl->privileged = true;
736         }
737
738         if (Cmd_Argc () != 2)
739                 return;
740
741         for (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++)
742         {
743                 if (!cl->active)
744                         continue;
745                 if (strcasecmp(cl->name, Cmd_Argv(1)) == 0)
746                 {
747                         if (cl->privileged)
748                         {
749                                 cl->privileged = false;
750                                 cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
751                                 cl->edict->v.movetype = MOVETYPE_WALK;
752                                 noclip_anglehack = false;
753                         }
754                         else
755                                 cl->privileged = true;
756                         break;
757                 }
758         }
759 }
760 #endif
761
762
763 void Host_Say(qboolean teamonly)
764 {
765         client_t *client;
766         client_t *save;
767         int             j;
768         char    *p;
769         // LordHavoc: 256 char say messages
770         unsigned char   text[256];
771         qboolean        fromServer = false;
772
773         if (cmd_source == src_command)
774         {
775                 if (cls.state == ca_dedicated)
776                 {
777                         fromServer = true;
778                         teamonly = false;
779                 }
780                 else
781                 {
782                         Cmd_ForwardToServer ();
783                         return;
784                 }
785         }
786
787         if (Cmd_Argc () < 2)
788                 return;
789
790         save = host_client;
791
792         p = Cmd_Args();
793 // remove quotes if present
794         if (*p == '"')
795         {
796                 p++;
797                 p[strlen(p)-1] = 0;
798         }
799
800 // turn on color set 1
801         if (!fromServer)
802                 sprintf (text, "%c%s: ", 1, save->name);
803         else
804                 sprintf (text, "%c<%s> ", 1, hostname.string);
805
806         j = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator
807         if (strlen(p) > j)
808                 p[j] = 0;
809
810         strcat (text, p);
811         strcat (text, "\n");
812
813         for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
814         {
815                 if (!client || !client->active || !client->spawned)
816                         continue;
817                 if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team)
818                         continue;
819                 host_client = client;
820                 SV_ClientPrintf("%s", text);
821         }
822         host_client = save;
823
824         Sys_Printf("%s", &text[1]);
825 }
826
827
828 void Host_Say_f(void)
829 {
830         Host_Say(false);
831 }
832
833
834 void Host_Say_Team_f(void)
835 {
836         Host_Say(true);
837 }
838
839
840 void Host_Tell_f(void)
841 {
842         client_t *client;
843         client_t *save;
844         int             j;
845         char    *p;
846         char    text[64];
847
848         if (cmd_source == src_command)
849         {
850                 Cmd_ForwardToServer ();
851                 return;
852         }
853
854         if (Cmd_Argc () < 3)
855                 return;
856
857         strcpy(text, host_client->name);
858         strcat(text, ": ");
859
860         p = Cmd_Args();
861
862 // remove quotes if present
863         if (*p == '"')
864         {
865                 p++;
866                 p[strlen(p)-1] = 0;
867         }
868
869 // check length & truncate if necessary
870         j = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator
871         if (strlen(p) > j)
872                 p[j] = 0;
873
874         strcat (text, p);
875         strcat (text, "\n");
876
877         save = host_client;
878         for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
879         {
880                 if (!client->active || !client->spawned)
881                         continue;
882                 if (Q_strcasecmp(client->name, Cmd_Argv(1)))
883                         continue;
884                 host_client = client;
885                 SV_ClientPrintf("%s", text);
886                 break;
887         }
888         host_client = save;
889 }
890
891
892 /*
893 ==================
894 Host_Color_f
895 ==================
896 */
897 void Host_Color_f(void)
898 {
899         int             top, bottom;
900         int             playercolor;
901         
902         if (Cmd_Argc() == 1)
903         {
904                 Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);
905                 Con_Printf ("color <0-13> [0-13]\n");
906                 return;
907         }
908
909         if (Cmd_Argc() == 2)
910                 top = bottom = atoi(Cmd_Argv(1));
911         else
912         {
913                 top = atoi(Cmd_Argv(1));
914                 bottom = atoi(Cmd_Argv(2));
915         }
916         
917         top &= 15;
918         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
919         if (top > 15)
920                 top = 15;
921         bottom &= 15;
922         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
923         if (bottom > 15)
924                 bottom = 15;
925         
926         playercolor = top*16 + bottom;
927
928         if (cmd_source == src_command)
929         {
930                 Cvar_SetValue ("_cl_color", playercolor);
931                 if (cls.state == ca_connected)
932                         Cmd_ForwardToServer ();
933                 return;
934         }
935
936         host_client->colors = playercolor;
937         host_client->edict->v.team = bottom + 1;
938
939 // send notification to all clients
940         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
941         MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
942         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
943 }
944
945 /*
946 ==================
947 Host_Kill_f
948 ==================
949 */
950 void Host_Kill_f (void)
951 {
952         if (cmd_source == src_command)
953         {
954                 Cmd_ForwardToServer ();
955                 return;
956         }
957
958         if (sv_player->v.health <= 0)
959         {
960                 SV_ClientPrintf ("Can't suicide -- allready dead!\n");
961                 return;
962         }
963         
964         pr_global_struct->time = sv.time;
965         pr_global_struct->self = EDICT_TO_PROG(sv_player);
966         PR_ExecuteProgram (pr_global_struct->ClientKill);
967 }
968
969
970 /*
971 ==================
972 Host_Pause_f
973 ==================
974 */
975 void Host_Pause_f (void)
976 {
977         
978         if (cmd_source == src_command)
979         {
980                 Cmd_ForwardToServer ();
981                 return;
982         }
983         if (!pausable.value)
984                 SV_ClientPrintf ("Pause not allowed.\n");
985         else
986         {
987                 sv.paused ^= 1;
988
989                 if (sv.paused)
990                 {
991                         SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->v.netname);
992                 }
993                 else
994                 {
995                         SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->v.netname);
996                 }
997
998         // send notification to all clients
999                 MSG_WriteByte (&sv.reliable_datagram, svc_setpause);
1000                 MSG_WriteByte (&sv.reliable_datagram, sv.paused);
1001         }
1002 }
1003
1004 //===========================================================================
1005
1006
1007 /*
1008 ==================
1009 Host_PreSpawn_f
1010 ==================
1011 */
1012 void Host_PreSpawn_f (void)
1013 {
1014         if (cmd_source == src_command)
1015         {
1016                 Con_Printf ("prespawn is not valid from the console\n");
1017                 return;
1018         }
1019
1020         if (host_client->spawned)
1021         {
1022                 Con_Printf ("prespawn not valid -- allready spawned\n");
1023                 return;
1024         }
1025         
1026         SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
1027         MSG_WriteByte (&host_client->message, svc_signonnum);
1028         MSG_WriteByte (&host_client->message, 2);
1029         host_client->sendsignon = true;
1030 }
1031
1032 dfunction_t *ED_FindFunction (char *name);
1033
1034 /*
1035 ==================
1036 Host_Spawn_f
1037 ==================
1038 */
1039 void Host_Spawn_f (void)
1040 {
1041         int             i;
1042         client_t        *client;
1043         edict_t *ent;
1044         func_t RestoreGame;
1045         dfunction_t *f;
1046
1047         if (cmd_source == src_command)
1048         {
1049                 Con_Printf ("spawn is not valid from the console\n");
1050                 return;
1051         }
1052
1053         if (host_client->spawned)
1054         {
1055                 Con_Printf ("Spawn not valid -- allready spawned\n");
1056                 return;
1057         }
1058
1059 // run the entrance script
1060         if (sv.loadgame)
1061         {       // loaded games are fully inited allready
1062                 // if this is the last client to be connected, unpause
1063                 sv.paused = false;
1064
1065                 if (f = ED_FindFunction ("RestoreGame"))
1066                 if (RestoreGame = (func_t)(f - pr_functions))
1067                 {
1068                         Con_DPrintf("Calling RestoreGame\n");
1069                         pr_global_struct->time = sv.time;
1070                         pr_global_struct->self = EDICT_TO_PROG(sv_player);
1071                         PR_ExecuteProgram (RestoreGame);
1072                 }
1073         }
1074         else
1075         {
1076                 eval_t *val;
1077                 // set up the edict
1078                 ent = host_client->edict;
1079
1080                 memset (&ent->v, 0, progs->entityfields * 4);
1081                 ent->v.colormap = NUM_FOR_EDICT(ent);
1082                 ent->v.team = (host_client->colors & 15) + 1;
1083                 ent->v.netname = host_client->name - pr_strings;
1084                 if (val = GETEDICTFIELDVALUE(host_client->edict, eval_pmodel))
1085                         val->_float = host_client->pmodel;
1086
1087                 // copy spawn parms out of the client_t
1088
1089                 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1090                         (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
1091
1092                 // call the spawn function
1093
1094                 pr_global_struct->time = sv.time;
1095                 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1096                 PR_ExecuteProgram (pr_global_struct->ClientConnect);
1097
1098                 if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time)
1099                         Sys_Printf ("%s entered the game\n", host_client->name);
1100
1101                 PR_ExecuteProgram (pr_global_struct->PutClientInServer);        
1102         }
1103
1104
1105 // send all current names, colors, and frag counts
1106         SZ_Clear (&host_client->message);
1107
1108 // send time of update
1109         MSG_WriteByte (&host_client->message, svc_time);
1110         MSG_WriteFloat (&host_client->message, sv.time);
1111
1112         for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
1113         {
1114                 MSG_WriteByte (&host_client->message, svc_updatename);
1115                 MSG_WriteByte (&host_client->message, i);
1116                 MSG_WriteString (&host_client->message, client->name);
1117                 MSG_WriteByte (&host_client->message, svc_updatefrags);
1118                 MSG_WriteByte (&host_client->message, i);
1119                 MSG_WriteShort (&host_client->message, client->old_frags);
1120                 MSG_WriteByte (&host_client->message, svc_updatecolors);
1121                 MSG_WriteByte (&host_client->message, i);
1122                 MSG_WriteByte (&host_client->message, client->colors);
1123         }
1124         
1125 // send all current light styles
1126         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1127         {
1128                 MSG_WriteByte (&host_client->message, svc_lightstyle);
1129                 MSG_WriteByte (&host_client->message, (char)i);
1130                 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1131         }
1132
1133 //
1134 // send some stats
1135 //
1136         MSG_WriteByte (&host_client->message, svc_updatestat);
1137         MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1138         MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
1139
1140         MSG_WriteByte (&host_client->message, svc_updatestat);
1141         MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1142         MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);
1143
1144         MSG_WriteByte (&host_client->message, svc_updatestat);
1145         MSG_WriteByte (&host_client->message, STAT_SECRETS);
1146         MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);
1147
1148         MSG_WriteByte (&host_client->message, svc_updatestat);
1149         MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1150         MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
1151
1152 //
1153 // send a fixangle
1154 // Never send a roll angle, because savegames can catch the server
1155 // in a state where it is expecting the client to correct the angle
1156 // and it won't happen if the game was just loaded, so you wind up
1157 // with a permanent head tilt
1158         ent = EDICT_NUM( 1 + (host_client - svs.clients) );
1159         MSG_WriteByte (&host_client->message, svc_setangle);
1160         for (i=0 ; i < 2 ; i++)
1161                 MSG_WriteAngle (&host_client->message, ent->v.angles[i] );
1162         MSG_WriteAngle (&host_client->message, 0 );
1163
1164         SV_WriteClientdataToMessage (sv_player, &host_client->message);
1165
1166         MSG_WriteByte (&host_client->message, svc_signonnum);
1167         MSG_WriteByte (&host_client->message, 3);
1168         host_client->sendsignon = true;
1169 }
1170
1171 /*
1172 ==================
1173 Host_Begin_f
1174 ==================
1175 */
1176 void Host_Begin_f (void)
1177 {
1178         if (cmd_source == src_command)
1179         {
1180                 Con_Printf ("begin is not valid from the console\n");
1181                 return;
1182         }
1183
1184         host_client->spawned = true;
1185 }
1186
1187 //===========================================================================
1188
1189
1190 /*
1191 ==================
1192 Host_Kick_f
1193
1194 Kicks a user off of the server
1195 ==================
1196 */
1197 void Host_Kick_f (void)
1198 {
1199         char            *who;
1200         char            *message = NULL;
1201         client_t        *save;
1202         int                     i;
1203         qboolean        byNumber = false;
1204
1205         if (cmd_source == src_command)
1206         {
1207                 if (!sv.active)
1208                 {
1209                         Cmd_ForwardToServer ();
1210                         return;
1211                 }
1212         }
1213         else if (pr_global_struct->deathmatch && !host_client->privileged)
1214                 return;
1215
1216         save = host_client;
1217
1218         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1219         {
1220                 i = atof(Cmd_Argv(2)) - 1;
1221                 if (i < 0 || i >= svs.maxclients)
1222                         return;
1223                 if (!svs.clients[i].active)
1224                         return;
1225                 host_client = &svs.clients[i];
1226                 byNumber = true;
1227         }
1228         else
1229         {
1230                 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
1231                 {
1232                         if (!host_client->active)
1233                                 continue;
1234                         if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1235                                 break;
1236                 }
1237         }
1238
1239         if (i < svs.maxclients)
1240         {
1241                 if (cmd_source == src_command)
1242                         if (cls.state == ca_dedicated)
1243                                 who = "Console";
1244                         else
1245                                 who = cl_name.string;
1246                 else
1247                         who = save->name;
1248
1249                 // can't kick yourself!
1250                 if (host_client == save)
1251                         return;
1252
1253                 if (Cmd_Argc() > 2)
1254                 {
1255                         message = COM_Parse(Cmd_Args());
1256                         if (byNumber)
1257                         {
1258                                 message++;                                                      // skip the #
1259                                 while (*message == ' ')                         // skip white space
1260                                         message++;
1261                                 message += strlen(Cmd_Argv(2)); // skip the number
1262                         }
1263                         while (*message && *message == ' ')
1264                                 message++;
1265                 }
1266                 if (message)
1267                         SV_ClientPrintf ("Kicked by %s: %s\n", who, message);
1268                 else
1269                         SV_ClientPrintf ("Kicked by %s\n", who);
1270                 SV_DropClient (false);
1271         }
1272
1273         host_client = save;
1274 }
1275
1276 /*
1277 ===============================================================================
1278
1279 DEBUGGING TOOLS
1280
1281 ===============================================================================
1282 */
1283
1284 /*
1285 ==================
1286 Host_Give_f
1287 ==================
1288 */
1289 void Host_Give_f (void)
1290 {
1291         char    *t;
1292         int             v;
1293         eval_t  *val;
1294
1295         if (cmd_source == src_command)
1296         {
1297                 Cmd_ForwardToServer ();
1298                 return;
1299         }
1300
1301         if (pr_global_struct->deathmatch && !host_client->privileged)
1302                 return;
1303
1304         t = Cmd_Argv(1);
1305         v = atoi (Cmd_Argv(2));
1306         
1307         switch (t[0])
1308         {
1309    case '0':
1310    case '1':
1311    case '2':
1312    case '3':
1313    case '4':
1314    case '5':
1315    case '6':
1316    case '7':
1317    case '8':
1318    case '9':
1319       // MED 01/04/97 added hipnotic give stuff
1320       if (hipnotic)
1321       {
1322          if (t[0] == '6')
1323          {
1324             if (t[1] == 'a')
1325                sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;
1326             else
1327                sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;
1328          }
1329          else if (t[0] == '9')
1330             sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;
1331          else if (t[0] == '0')
1332             sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;
1333          else if (t[0] >= '2')
1334             sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
1335       }
1336       else
1337       {
1338          if (t[0] >= '2')
1339             sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
1340       }
1341                 break;
1342         
1343     case 's':
1344                 if (rogue)
1345                 {
1346                     if (val = GETEDICTFIELDVALUE(sv_player, eval_ammo_shells1))
1347                             val->_float = v;
1348                 }
1349
1350         sv_player->v.ammo_shells = v;
1351         break;          
1352     case 'n':
1353                 if (rogue)
1354                 {
1355                     if (val = GETEDICTFIELDVALUE(sv_player, eval_ammo_nails1))
1356                         {
1357                             val->_float = v;
1358                                 if (sv_player->v.weapon <= IT_LIGHTNING)
1359                                         sv_player->v.ammo_nails = v;
1360                         }
1361                 }
1362                 else
1363                 {
1364                         sv_player->v.ammo_nails = v;
1365                 }
1366         break;          
1367     case 'l':
1368                 if (rogue)
1369                 {
1370                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_lava_nails);
1371                         if (val)
1372                         {
1373                                 val->_float = v;
1374                                 if (sv_player->v.weapon > IT_LIGHTNING)
1375                                         sv_player->v.ammo_nails = v;
1376                         }
1377                 }
1378         break;
1379     case 'r':
1380                 if (rogue)
1381                 {
1382                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_rockets1);
1383                         if (val)
1384                         {
1385                                 val->_float = v;
1386                                 if (sv_player->v.weapon <= IT_LIGHTNING)
1387                                         sv_player->v.ammo_rockets = v;
1388                         }
1389                 }
1390                 else
1391                 {
1392                         sv_player->v.ammo_rockets = v;
1393                 }
1394         break;          
1395     case 'm':
1396                 if (rogue)
1397                 {
1398                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_multi_rockets);
1399                         if (val)
1400                         {
1401                                 val->_float = v;
1402                                 if (sv_player->v.weapon > IT_LIGHTNING)
1403                                         sv_player->v.ammo_rockets = v;
1404                         }
1405                 }
1406         break;          
1407     case 'h':
1408         sv_player->v.health = v;
1409         break;          
1410     case 'c':
1411                 if (rogue)
1412                 {
1413                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_cells1);
1414                         if (val)
1415                         {
1416                                 val->_float = v;
1417                                 if (sv_player->v.weapon <= IT_LIGHTNING)
1418                                         sv_player->v.ammo_cells = v;
1419                         }
1420                 }
1421                 else
1422                 {
1423                         sv_player->v.ammo_cells = v;
1424                 }
1425         break;          
1426     case 'p':
1427                 if (rogue)
1428                 {
1429                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_plasma);
1430                         if (val)
1431                         {
1432                                 val->_float = v;
1433                                 if (sv_player->v.weapon > IT_LIGHTNING)
1434                                         sv_player->v.ammo_cells = v;
1435                         }
1436                 }
1437         break;          
1438     }
1439 }
1440
1441 edict_t *FindViewthing (void)
1442 {
1443         int             i;
1444         edict_t *e;
1445         
1446         for (i=0 ; i<sv.num_edicts ; i++)
1447         {
1448                 e = EDICT_NUM(i);
1449                 if ( !strcmp (pr_strings + e->v.classname, "viewthing") )
1450                         return e;
1451         }
1452         Con_Printf ("No viewthing on map\n");
1453         return NULL;
1454 }
1455
1456 /*
1457 ==================
1458 Host_Viewmodel_f
1459 ==================
1460 */
1461 void Host_Viewmodel_f (void)
1462 {
1463         edict_t *e;
1464         model_t *m;
1465
1466         e = FindViewthing ();
1467         if (!e)
1468                 return;
1469
1470         m = Mod_ForName (Cmd_Argv(1), false);
1471         if (!m)
1472         {
1473                 Con_Printf ("Can't load %s\n", Cmd_Argv(1));
1474                 return;
1475         }
1476         
1477         e->v.frame = 0;
1478         cl.model_precache[(int)e->v.modelindex] = m;
1479 }
1480
1481 /*
1482 ==================
1483 Host_Viewframe_f
1484 ==================
1485 */
1486 void Host_Viewframe_f (void)
1487 {
1488         edict_t *e;
1489         int             f;
1490         model_t *m;
1491
1492         e = FindViewthing ();
1493         if (!e)
1494                 return;
1495         m = cl.model_precache[(int)e->v.modelindex];
1496
1497         f = atoi(Cmd_Argv(1));
1498         if (f >= m->numframes)
1499                 f = m->numframes-1;
1500
1501         e->v.frame = f;         
1502 }
1503
1504
1505 void PrintFrameName (model_t *m, int frame)
1506 {
1507         aliashdr_t                      *hdr;
1508         maliasframedesc_t       *pframedesc;
1509
1510         hdr = (aliashdr_t *)Mod_Extradata (m);
1511         if (!hdr)
1512                 return;
1513         pframedesc = &hdr->frames[frame];
1514         
1515         Con_Printf ("frame %i: %s\n", frame, pframedesc->name);
1516 }
1517
1518 /*
1519 ==================
1520 Host_Viewnext_f
1521 ==================
1522 */
1523 void Host_Viewnext_f (void)
1524 {
1525         edict_t *e;
1526         model_t *m;
1527         
1528         e = FindViewthing ();
1529         if (!e)
1530                 return;
1531         m = cl.model_precache[(int)e->v.modelindex];
1532
1533         e->v.frame = e->v.frame + 1;
1534         if (e->v.frame >= m->numframes)
1535                 e->v.frame = m->numframes - 1;
1536
1537         PrintFrameName (m, e->v.frame);         
1538 }
1539
1540 /*
1541 ==================
1542 Host_Viewprev_f
1543 ==================
1544 */
1545 void Host_Viewprev_f (void)
1546 {
1547         edict_t *e;
1548         model_t *m;
1549
1550         e = FindViewthing ();
1551         if (!e)
1552                 return;
1553
1554         m = cl.model_precache[(int)e->v.modelindex];
1555
1556         e->v.frame = e->v.frame - 1;
1557         if (e->v.frame < 0)
1558                 e->v.frame = 0;
1559
1560         PrintFrameName (m, e->v.frame);         
1561 }
1562
1563 /*
1564 ===============================================================================
1565
1566 DEMO LOOP CONTROL
1567
1568 ===============================================================================
1569 */
1570
1571
1572 /*
1573 ==================
1574 Host_Startdemos_f
1575 ==================
1576 */
1577 void Host_Startdemos_f (void)
1578 {
1579         int             i, c;
1580
1581         if (cls.state == ca_dedicated)
1582         {
1583                 if (!sv.active)
1584                         Cbuf_AddText ("map start\n");
1585                 return;
1586         }
1587
1588         c = Cmd_Argc() - 1;
1589         if (c > MAX_DEMOS)
1590         {
1591                 Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS);
1592                 c = MAX_DEMOS;
1593         }
1594         Con_Printf ("%i demo(s) in loop\n", c);
1595
1596         for (i=1 ; i<c+1 ; i++)
1597                 strncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1);
1598
1599         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1600         {
1601                 cls.demonum = 0;
1602                 CL_NextDemo ();
1603         }
1604         else
1605                 cls.demonum = -1;
1606 }
1607
1608
1609 /*
1610 ==================
1611 Host_Demos_f
1612
1613 Return to looping demos
1614 ==================
1615 */
1616 void Host_Demos_f (void)
1617 {
1618         if (cls.state == ca_dedicated)
1619                 return;
1620         if (cls.demonum == -1)
1621                 cls.demonum = 1;
1622         CL_Disconnect_f ();
1623         CL_NextDemo ();
1624 }
1625
1626 /*
1627 ==================
1628 Host_Stopdemo_f
1629
1630 Return to looping demos
1631 ==================
1632 */
1633 void Host_Stopdemo_f (void)
1634 {
1635         if (cls.state == ca_dedicated)
1636                 return;
1637         if (!cls.demoplayback)
1638                 return;
1639         CL_StopPlayback ();
1640         CL_Disconnect ();
1641 }
1642
1643 //=============================================================================
1644
1645 /*
1646 ==================
1647 Host_InitCommands
1648 ==================
1649 */
1650 void Host_InitCommands (void)
1651 {
1652         Cmd_AddCommand ("status", Host_Status_f);
1653         Cmd_AddCommand ("quit", Host_Quit_f);
1654         if (nehahra)
1655         {
1656                 Cmd_AddCommand ("max", Host_God_f);
1657                 Cmd_AddCommand ("monster", Host_Notarget_f);
1658                 Cmd_AddCommand ("scrag", Host_Fly_f);
1659                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1660                 Cmd_AddCommand ("gimme", Host_Give_f);
1661         }
1662         else
1663         {
1664                 Cmd_AddCommand ("god", Host_God_f);
1665                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1666                 Cmd_AddCommand ("fly", Host_Fly_f);
1667                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1668                 Cmd_AddCommand ("give", Host_Give_f);
1669         }
1670         Cmd_AddCommand ("map", Host_Map_f);
1671         Cmd_AddCommand ("restart", Host_Restart_f);
1672         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1673         Cmd_AddCommand ("connect", Host_Connect_f);
1674         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1675         Cmd_AddCommand ("name", Host_Name_f);
1676         Cmd_AddCommand ("version", Host_Version_f);
1677 #ifdef IDGODS
1678         Cmd_AddCommand ("please", Host_Please_f);
1679 #endif
1680         Cmd_AddCommand ("say", Host_Say_f);
1681         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1682         Cmd_AddCommand ("tell", Host_Tell_f);
1683         Cmd_AddCommand ("color", Host_Color_f);
1684         Cmd_AddCommand ("kill", Host_Kill_f);
1685         Cmd_AddCommand ("pause", Host_Pause_f);
1686         Cmd_AddCommand ("spawn", Host_Spawn_f);
1687         Cmd_AddCommand ("begin", Host_Begin_f);
1688         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1689         Cmd_AddCommand ("kick", Host_Kick_f);
1690         Cmd_AddCommand ("ping", Host_Ping_f);
1691         Cmd_AddCommand ("load", Host_Loadgame_f);
1692         Cmd_AddCommand ("save", Host_Savegame_f);
1693
1694         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1695         Cmd_AddCommand ("demos", Host_Demos_f);
1696         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1697
1698         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1699         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1700         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1701         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1702
1703         Cmd_AddCommand ("mcache", Mod_Print);
1704 }