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