]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - host_cmd.c
*** empty log message ***
[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 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 || !sv_player)
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 || !sv_player)
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 || !sv_player)
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 || !sv_player)
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         CL_Disconnect ();
254         Host_ShutdownServer(false);
255
256         key_dest = key_game;                    // remove console or menu
257         SCR_BeginLoadingPlaque ();
258
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 (strcmp(host_client->name, newName) && host_client->name[0] && strcmp(host_client->name, "unconnected"))
658                 SV_BroadcastPrintf("%s changed name to %s\n", host_client->name, newName);
659         strcpy(host_client->name, newName);
660         strcpy(host_client->old_name, newName);
661         if (sv_player)
662                 sv_player->v->netname = PR_SetString(host_client->name);
663         //Con_Printf("Host_Name_f: host_client->edict->netname = %s, sv_player->netname = %s, host_client->name = %s\n", PR_GetString(host_client->edict->v->netname), PR_GetString(sv_player->v->netname), host_client->name);
664
665 // send notification to all clients
666
667         MSG_WriteByte(&sv.reliable_datagram, svc_updatename);
668         MSG_WriteByte(&sv.reliable_datagram, host_client - svs.clients);
669         MSG_WriteString(&sv.reliable_datagram, host_client->name);
670 }
671
672
673 void Host_Version_f (void)
674 {
675         Con_Printf ("Version: %s build %s\n", gamename, buildstring);
676 }
677
678 void Host_Say(qboolean teamonly)
679 {
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         save = host_client;
705
706 // turn on color set 1
707         if (!fromServer)
708                 sprintf (text, "%c%s: ", 1, host_client->name);
709         else
710                 sprintf (text, "%c<%s> ", 1, hostname.string);
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 if (fromServer)
724                         Con_Printf("Host_Say: missing end quote\n");
725                 else
726                         SV_ClientPrintf("Host_Say: missing end quote\n");
727         }
728         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
729                 p2--;
730         for (j = strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
731                 text[j++] = *p1++;
732         text[j++] = '\n';
733         text[j++] = 0;
734
735         for (j = 0, host_client = svs.clients; j < svs.maxclients; j++, host_client++)
736                 if (host_client && host_client->active && host_client->spawned && (!teamplay.integer || host_client->edict->v->team == save->edict->v->team))
737                         SV_ClientPrintf("%s", text);
738         host_client = save;
739
740         Sys_Printf("%s", &text[1]);
741 }
742
743
744 void Host_Say_f(void)
745 {
746         Host_Say(false);
747 }
748
749
750 void Host_Say_Team_f(void)
751 {
752         Host_Say(true);
753 }
754
755
756 void Host_Tell_f(void)
757 {
758         client_t *save;
759         int j;
760         const char *p1, *p2;
761         char text[1024]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
762         qboolean fromServer = false;
763
764         if (cmd_source == src_command)
765         {
766                 if (cls.state == ca_dedicated)
767                         fromServer = true;
768                 else
769                 {
770                         Cmd_ForwardToServer ();
771                         return;
772                 }
773         }
774
775         if (Cmd_Argc () < 3)
776                 return;
777
778         if (!fromServer)
779                 sprintf (text, "%s: ", host_client->name);
780         else
781                 sprintf (text, "<%s> ", hostname.string);
782
783         p1 = Cmd_Args();
784         p2 = p1 + strlen(p1);
785         // remove the target name
786         while (p1 < p2 && *p1 != ' ')
787                 p1++;
788         while (p1 < p2 && *p1 == ' ')
789                 p1++;
790         // remove trailing newlines
791         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
792                 p2--;
793         // remove quotes if present
794         if (*p1 == '"')
795         {
796                 p1++;
797                 if (p2[-1] == '"')
798                         p2--;
799                 else if (fromServer)
800                         Con_Printf("Host_Tell: missing end quote\n");
801                 else
802                         SV_ClientPrintf("Host_Tell: missing end quote\n");
803         }
804         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
805                 p2--;
806         for (j = strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
807                 text[j++] = *p1++;
808         text[j++] = '\n';
809         text[j++] = 0;
810
811         save = host_client;
812         for (j = 0, host_client = svs.clients; j < svs.maxclients; j++, host_client++)
813         {
814                 if (host_client->active && host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
815                 {
816                         SV_ClientPrintf("%s", text);
817                         break;
818                 }
819         }
820         host_client = save;
821 }
822
823
824 /*
825 ==================
826 Host_Color_f
827 ==================
828 */
829 cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
830 void Host_Color_f(void)
831 {
832         int             top, bottom;
833         int             playercolor;
834         mfunction_t *f;
835         func_t  SV_ChangeTeam;
836
837         if (Cmd_Argc() == 1)
838         {
839                 Con_Printf ("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
840                 Con_Printf ("color <0-15> [0-15]\n");
841                 return;
842         }
843
844         if (Cmd_Argc() == 2)
845                 top = bottom = atoi(Cmd_Argv(1));
846         else
847         {
848                 top = atoi(Cmd_Argv(1));
849                 bottom = atoi(Cmd_Argv(2));
850         }
851
852         top &= 15;
853         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
854         if (top > 15)
855                 top = 15;
856         bottom &= 15;
857         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
858         if (bottom > 15)
859                 bottom = 15;
860
861         playercolor = top*16 + bottom;
862
863         if (cmd_source == src_command)
864         {
865                 Cvar_SetValue ("_cl_color", playercolor);
866                 if (cls.state == ca_connected)
867                         Cmd_ForwardToServer ();
868                 return;
869         }
870
871         if (sv_player && (f = ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - pr_functions)))
872         {
873                 Con_DPrintf("Calling SV_ChangeTeam\n");
874                 pr_global_struct->time = sv.time;
875                 pr_globals[OFS_PARM0] = playercolor;
876                 pr_global_struct->self = EDICT_TO_PROG(sv_player);
877                 PR_ExecuteProgram (SV_ChangeTeam, "");
878         }
879         else
880         {
881                 eval_t *val;
882                 if (sv_player)
883                 {
884                         if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)))
885                                 val->_float = playercolor;
886                         sv_player->v->team = bottom + 1;
887                 }
888                 host_client->colors = playercolor;
889                 host_client->old_colors = playercolor;
890
891                 // send notification to all clients
892                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
893                 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
894                 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
895         }
896 }
897
898 /*
899 ==================
900 Host_Kill_f
901 ==================
902 */
903 void Host_Kill_f (void)
904 {
905         if (cmd_source == src_command)
906         {
907                 Cmd_ForwardToServer ();
908                 return;
909         }
910
911         if (!sv_player || sv_player->v->health <= 0)
912         {
913                 SV_ClientPrintf ("Can't suicide -- already dead!\n");
914                 return;
915         }
916
917         pr_global_struct->time = sv.time;
918         pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
919         PR_ExecuteProgram (pr_global_struct->ClientKill, "QC function ClientKill is missing");
920 }
921
922
923 /*
924 ==================
925 Host_Pause_f
926 ==================
927 */
928 void Host_Pause_f (void)
929 {
930
931         if (cmd_source == src_command)
932         {
933                 Cmd_ForwardToServer ();
934                 return;
935         }
936         if (!pausable.integer)
937                 SV_ClientPrintf ("Pause not allowed.\n");
938         else
939         {
940                 sv.paused ^= 1;
941                 SV_BroadcastPrintf ("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
942                 // send notification to all clients
943                 MSG_WriteByte (&sv.reliable_datagram, svc_setpause);
944                 MSG_WriteByte (&sv.reliable_datagram, sv.paused);
945         }
946 }
947
948 /*
949 ======================
950 Host_PModel_f
951 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
952 ======================
953 */
954 cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
955 static void Host_PModel_f (void)
956 {
957         int i;
958         eval_t *val;
959
960         if (Cmd_Argc () == 1)
961         {
962                 Con_Printf ("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
963                 return;
964         }
965         i = atoi(Cmd_Argv(1));
966
967         if (cmd_source == src_command)
968         {
969                 if (cl_pmodel.integer == i)
970                         return;
971                 Cvar_SetValue ("_cl_pmodel", i);
972                 if (cls.state == ca_connected)
973                         Cmd_ForwardToServer ();
974                 return;
975         }
976
977         host_client->pmodel = i;
978         if (sv_player && (val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)))
979                 val->_float = i;
980 }
981
982 //===========================================================================
983
984
985 /*
986 ==================
987 Host_PreSpawn_f
988 ==================
989 */
990 void Host_PreSpawn_f (void)
991 {
992         if (cmd_source == src_command)
993         {
994                 Con_Printf ("prespawn is not valid from the console\n");
995                 return;
996         }
997
998         if (host_client->spawned)
999         {
1000                 Con_Printf ("prespawn not valid -- already spawned\n");
1001                 return;
1002         }
1003
1004         SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
1005         MSG_WriteByte (&host_client->message, svc_signonnum);
1006         MSG_WriteByte (&host_client->message, 2);
1007         host_client->sendsignon = true;
1008 }
1009
1010 /*
1011 ==================
1012 Host_Spawn_f
1013 ==================
1014 */
1015 void Host_Spawn_f (void)
1016 {
1017         int i;
1018         client_t *client;
1019         func_t RestoreGame;
1020         mfunction_t *f;
1021
1022         if (cmd_source == src_command)
1023         {
1024                 Con_Printf("spawn is not valid from the console\n");
1025                 return;
1026         }
1027
1028         if (host_client->spawned)
1029         {
1030                 Con_Printf("Spawn not valid -- already spawned\n");
1031                 return;
1032         }
1033
1034         if (!sv_player)
1035         {
1036                 Con_Printf("Host_Spawn: no edict??\n");
1037                 return;
1038         }
1039
1040         // LordHavoc: moved this above the QC calls at FrikaC's request
1041         // send all current names, colors, and frag counts
1042         SZ_Clear (&host_client->message);
1043
1044         // run the entrance script
1045         if (sv.loadgame)
1046         {
1047                 // loaded games are fully initialized already
1048                 // if this is the last client to be connected, unpause
1049                 sv.paused = false;
1050
1051                 if ((f = ED_FindFunction ("RestoreGame")))
1052                 if ((RestoreGame = (func_t)(f - pr_functions)))
1053                 {
1054                         Con_DPrintf("Calling RestoreGame\n");
1055                         pr_global_struct->time = sv.time;
1056                         pr_global_struct->self = EDICT_TO_PROG(sv_player);
1057                         PR_ExecuteProgram (RestoreGame, "");
1058                 }
1059         }
1060         else
1061         {
1062                 // set up the edict
1063                 ED_ClearEdict(sv_player);
1064
1065                 //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, sv_player->netname = %s, host_client->name = %s\n", PR_GetString(host_client->edict->v->netname), PR_GetString(sv_player->v->netname), host_client->name);
1066
1067                 // copy spawn parms out of the client_t
1068                 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1069                         (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
1070
1071                 // call the spawn function
1072                 pr_global_struct->time = sv.time;
1073                 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1074                 PR_ExecuteProgram (pr_global_struct->ClientConnect, "QC function ClientConnect is missing");
1075
1076                 if ((Sys_DoubleTime() - host_client->netconnection->connecttime) <= sv.time)
1077                         Sys_Printf ("%s entered the game\n", host_client->name);
1078
1079                 PR_ExecuteProgram (pr_global_struct->PutClientInServer, "QC function PutClientInServer is missing");
1080         }
1081
1082
1083         // send time of update
1084         MSG_WriteByte (&host_client->message, svc_time);
1085         MSG_WriteFloat (&host_client->message, sv.time);
1086
1087         for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
1088         {
1089                 MSG_WriteByte (&host_client->message, svc_updatename);
1090                 MSG_WriteByte (&host_client->message, i);
1091                 MSG_WriteString (&host_client->message, client->old_name);
1092                 MSG_WriteByte (&host_client->message, svc_updatefrags);
1093                 MSG_WriteByte (&host_client->message, i);
1094                 MSG_WriteShort (&host_client->message, client->old_frags);
1095                 MSG_WriteByte (&host_client->message, svc_updatecolors);
1096                 MSG_WriteByte (&host_client->message, i);
1097                 MSG_WriteByte (&host_client->message, client->old_colors);
1098         }
1099
1100         // send all current light styles
1101         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1102         {
1103                 MSG_WriteByte (&host_client->message, svc_lightstyle);
1104                 MSG_WriteByte (&host_client->message, (char)i);
1105                 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1106         }
1107
1108         // send some stats
1109         MSG_WriteByte (&host_client->message, svc_updatestat);
1110         MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1111         MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
1112
1113         MSG_WriteByte (&host_client->message, svc_updatestat);
1114         MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1115         MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);
1116
1117         MSG_WriteByte (&host_client->message, svc_updatestat);
1118         MSG_WriteByte (&host_client->message, STAT_SECRETS);
1119         MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);
1120
1121         MSG_WriteByte (&host_client->message, svc_updatestat);
1122         MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1123         MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
1124
1125         // send a fixangle
1126         // Never send a roll angle, because savegames can catch the server
1127         // in a state where it is expecting the client to correct the angle
1128         // and it won't happen if the game was just loaded, so you wind up
1129         // with a permanent head tilt
1130         MSG_WriteByte (&host_client->message, svc_setangle);
1131         for (i=0 ; i < 2 ; i++)
1132                 MSG_WriteAngle (&host_client->message, sv_player->v->angles[i] );
1133         MSG_WriteAngle (&host_client->message, 0 );
1134
1135         SV_WriteClientdataToMessage (sv_player, &host_client->message);
1136
1137         MSG_WriteByte (&host_client->message, svc_signonnum);
1138         MSG_WriteByte (&host_client->message, 3);
1139         host_client->sendsignon = true;
1140 }
1141
1142 /*
1143 ==================
1144 Host_Begin_f
1145 ==================
1146 */
1147 void Host_Begin_f (void)
1148 {
1149         if (cmd_source == src_command)
1150         {
1151                 Con_Printf ("begin is not valid from the console\n");
1152                 return;
1153         }
1154
1155         host_client->spawned = true;
1156 }
1157
1158 //===========================================================================
1159
1160
1161 /*
1162 ==================
1163 Host_Kick_f
1164
1165 Kicks a user off of the server
1166 ==================
1167 */
1168 void Host_Kick_f (void)
1169 {
1170         char *who;
1171         const char *message = NULL;
1172         client_t *save;
1173         int i;
1174         qboolean byNumber = false;
1175
1176         if (cmd_source == src_command)
1177         {
1178                 if (!sv.active)
1179                 {
1180                         Cmd_ForwardToServer ();
1181                         return;
1182                 }
1183         }
1184         else if (pr_global_struct->deathmatch)
1185                 return;
1186
1187         save = host_client;
1188
1189         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1190         {
1191                 i = atof(Cmd_Argv(2)) - 1;
1192                 if (i < 0 || i >= svs.maxclients)
1193                         return;
1194                 if (!svs.clients[i].active)
1195                         return;
1196                 host_client = &svs.clients[i];
1197                 byNumber = true;
1198         }
1199         else
1200         {
1201                 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
1202                 {
1203                         if (!host_client->active)
1204                                 continue;
1205                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1206                                 break;
1207                 }
1208         }
1209
1210         if (i < svs.maxclients)
1211         {
1212                 if (cmd_source == src_command)
1213                 {
1214                         if (cls.state == ca_dedicated)
1215                                 who = "Console";
1216                         else
1217                                 who = cl_name.string;
1218                 }
1219                 else
1220                         who = save->name;
1221
1222                 // can't kick yourself!
1223                 if (host_client == save)
1224                         return;
1225
1226                 if (Cmd_Argc() > 2)
1227                 {
1228                         message = Cmd_Args();
1229                         COM_ParseToken(&message);
1230                         if (byNumber)
1231                         {
1232                                 message++;                                                      // skip the #
1233                                 while (*message == ' ')                         // skip white space
1234                                         message++;
1235                                 message += strlen(Cmd_Argv(2)); // skip the number
1236                         }
1237                         while (*message && *message == ' ')
1238                                 message++;
1239                 }
1240                 if (message)
1241                         SV_ClientPrintf ("Kicked by %s: %s\n", who, message);
1242                 else
1243                         SV_ClientPrintf ("Kicked by %s\n", who);
1244                 SV_DropClient (false); // kicked
1245         }
1246
1247         host_client = save;
1248 }
1249
1250 /*
1251 ===============================================================================
1252
1253 DEBUGGING TOOLS
1254
1255 ===============================================================================
1256 */
1257
1258 /*
1259 ==================
1260 Host_Give_f
1261 ==================
1262 */
1263 void Host_Give_f (void)
1264 {
1265         const char *t;
1266         int v;
1267         eval_t *val;
1268
1269         if (cmd_source == src_command)
1270         {
1271                 Cmd_ForwardToServer ();
1272                 return;
1273         }
1274
1275         if (pr_global_struct->deathmatch || !sv_player)
1276                 return;
1277
1278         t = Cmd_Argv(1);
1279         v = atoi (Cmd_Argv(2));
1280
1281         switch (t[0])
1282         {
1283         case '0':
1284         case '1':
1285         case '2':
1286         case '3':
1287         case '4':
1288         case '5':
1289         case '6':
1290         case '7':
1291         case '8':
1292         case '9':
1293                 // MED 01/04/97 added hipnotic give stuff
1294                 if (gamemode == GAME_HIPNOTIC)
1295                 {
1296                         if (t[0] == '6')
1297                         {
1298                                 if (t[1] == 'a')
1299                                         sv_player->v->items = (int)sv_player->v->items | HIT_PROXIMITY_GUN;
1300                                 else
1301                                         sv_player->v->items = (int)sv_player->v->items | IT_GRENADE_LAUNCHER;
1302                         }
1303                         else if (t[0] == '9')
1304                                 sv_player->v->items = (int)sv_player->v->items | HIT_LASER_CANNON;
1305                         else if (t[0] == '0')
1306                                 sv_player->v->items = (int)sv_player->v->items | HIT_MJOLNIR;
1307                         else if (t[0] >= '2')
1308                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1309                 }
1310                 else
1311                 {
1312                         if (t[0] >= '2')
1313                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1314                 }
1315                 break;
1316
1317         case 's':
1318                 if (gamemode == GAME_ROGUE && (val = GETEDICTFIELDVALUE(sv_player, eval_ammo_shells1)))
1319                         val->_float = v;
1320
1321                 sv_player->v->ammo_shells = v;
1322                 break;
1323         case 'n':
1324                 if (gamemode == GAME_ROGUE)
1325                 {
1326                         if ((val = GETEDICTFIELDVALUE(sv_player, eval_ammo_nails1)))
1327                         {
1328                                 val->_float = v;
1329                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1330                                         sv_player->v->ammo_nails = v;
1331                         }
1332                 }
1333                 else
1334                 {
1335                         sv_player->v->ammo_nails = v;
1336                 }
1337                 break;
1338         case 'l':
1339                 if (gamemode == GAME_ROGUE)
1340                 {
1341                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_lava_nails);
1342                         if (val)
1343                         {
1344                                 val->_float = v;
1345                                 if (sv_player->v->weapon > IT_LIGHTNING)
1346                                         sv_player->v->ammo_nails = v;
1347                         }
1348                 }
1349                 break;
1350         case 'r':
1351                 if (gamemode == GAME_ROGUE)
1352                 {
1353                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_rockets1);
1354                         if (val)
1355                         {
1356                                 val->_float = v;
1357                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1358                                         sv_player->v->ammo_rockets = v;
1359                         }
1360                 }
1361                 else
1362                 {
1363                         sv_player->v->ammo_rockets = v;
1364                 }
1365                 break;
1366         case 'm':
1367                 if (gamemode == GAME_ROGUE)
1368                 {
1369                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_multi_rockets);
1370                         if (val)
1371                         {
1372                                 val->_float = v;
1373                                 if (sv_player->v->weapon > IT_LIGHTNING)
1374                                         sv_player->v->ammo_rockets = v;
1375                         }
1376                 }
1377                 break;
1378         case 'h':
1379                 sv_player->v->health = v;
1380                 break;
1381         case 'c':
1382                 if (gamemode == GAME_ROGUE)
1383                 {
1384                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_cells1);
1385                         if (val)
1386                         {
1387                                 val->_float = v;
1388                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1389                                         sv_player->v->ammo_cells = v;
1390                         }
1391                 }
1392                 else
1393                 {
1394                         sv_player->v->ammo_cells = v;
1395                 }
1396                 break;
1397         case 'p':
1398                 if (gamemode == GAME_ROGUE)
1399                 {
1400                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_plasma);
1401                         if (val)
1402                         {
1403                                 val->_float = v;
1404                                 if (sv_player->v->weapon > IT_LIGHTNING)
1405                                         sv_player->v->ammo_cells = v;
1406                         }
1407                 }
1408                 break;
1409         }
1410 }
1411
1412 edict_t *FindViewthing (void)
1413 {
1414         int             i;
1415         edict_t *e;
1416
1417         for (i=0 ; i<sv.num_edicts ; i++)
1418         {
1419                 e = EDICT_NUM(i);
1420                 if (!strcmp (PR_GetString(e->v->classname), "viewthing"))
1421                         return e;
1422         }
1423         Con_Printf ("No viewthing on map\n");
1424         return NULL;
1425 }
1426
1427 /*
1428 ==================
1429 Host_Viewmodel_f
1430 ==================
1431 */
1432 void Host_Viewmodel_f (void)
1433 {
1434         edict_t *e;
1435         model_t *m;
1436
1437         e = FindViewthing ();
1438         if (!e)
1439                 return;
1440
1441         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1442         if (!m)
1443         {
1444                 Con_Printf ("Can't load %s\n", Cmd_Argv(1));
1445                 return;
1446         }
1447
1448         e->v->frame = 0;
1449         cl.model_precache[(int)e->v->modelindex] = m;
1450 }
1451
1452 /*
1453 ==================
1454 Host_Viewframe_f
1455 ==================
1456 */
1457 void Host_Viewframe_f (void)
1458 {
1459         edict_t *e;
1460         int             f;
1461         model_t *m;
1462
1463         e = FindViewthing ();
1464         if (!e)
1465                 return;
1466         m = cl.model_precache[(int)e->v->modelindex];
1467
1468         f = atoi(Cmd_Argv(1));
1469         if (f >= m->numframes)
1470                 f = m->numframes-1;
1471
1472         e->v->frame = f;
1473 }
1474
1475
1476 void PrintFrameName (model_t *m, int frame)
1477 {
1478         if (m->animscenes)
1479                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1480         else
1481                 Con_Printf("frame %i\n", frame);
1482 }
1483
1484 /*
1485 ==================
1486 Host_Viewnext_f
1487 ==================
1488 */
1489 void Host_Viewnext_f (void)
1490 {
1491         edict_t *e;
1492         model_t *m;
1493
1494         e = FindViewthing ();
1495         if (!e)
1496                 return;
1497         m = cl.model_precache[(int)e->v->modelindex];
1498
1499         e->v->frame = e->v->frame + 1;
1500         if (e->v->frame >= m->numframes)
1501                 e->v->frame = m->numframes - 1;
1502
1503         PrintFrameName (m, e->v->frame);
1504 }
1505
1506 /*
1507 ==================
1508 Host_Viewprev_f
1509 ==================
1510 */
1511 void Host_Viewprev_f (void)
1512 {
1513         edict_t *e;
1514         model_t *m;
1515
1516         e = FindViewthing ();
1517         if (!e)
1518                 return;
1519
1520         m = cl.model_precache[(int)e->v->modelindex];
1521
1522         e->v->frame = e->v->frame - 1;
1523         if (e->v->frame < 0)
1524                 e->v->frame = 0;
1525
1526         PrintFrameName (m, e->v->frame);
1527 }
1528
1529 /*
1530 ===============================================================================
1531
1532 DEMO LOOP CONTROL
1533
1534 ===============================================================================
1535 */
1536
1537
1538 /*
1539 ==================
1540 Host_Startdemos_f
1541 ==================
1542 */
1543 void Host_Startdemos_f (void)
1544 {
1545         int             i, c;
1546
1547         if (cls.state == ca_dedicated)
1548         {
1549                 if (!sv.active && !sv_spawnmap[0])
1550                 {
1551                         if (gamemode == GAME_TRANSFUSION)
1552                                 Cbuf_AddText ("map bb1\n");
1553                         else
1554                                 Cbuf_AddText ("map start\n");
1555                 }
1556                 return;
1557         }
1558
1559         c = Cmd_Argc() - 1;
1560         if (c > MAX_DEMOS)
1561         {
1562                 Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS);
1563                 c = MAX_DEMOS;
1564         }
1565         Con_DPrintf ("%i demo(s) in loop\n", c);
1566
1567         for (i=1 ; i<c+1 ; i++)
1568                 strncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1);
1569
1570         // LordHavoc: clear the remaining slots
1571         for (;i <= MAX_DEMOS;i++)
1572                 cls.demos[i-1][0] = 0;
1573
1574         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1575         {
1576                 cls.demonum = 0;
1577                 CL_NextDemo ();
1578         }
1579         else
1580                 cls.demonum = -1;
1581 }
1582
1583
1584 /*
1585 ==================
1586 Host_Demos_f
1587
1588 Return to looping demos
1589 ==================
1590 */
1591 void Host_Demos_f (void)
1592 {
1593         if (cls.state == ca_dedicated)
1594                 return;
1595         if (cls.demonum == -1)
1596                 cls.demonum = 1;
1597         CL_Disconnect_f ();
1598         CL_NextDemo ();
1599 }
1600
1601 /*
1602 ==================
1603 Host_Stopdemo_f
1604
1605 Return to looping demos
1606 ==================
1607 */
1608 void Host_Stopdemo_f (void)
1609 {
1610         if (!cls.demoplayback)
1611                 return;
1612         CL_Disconnect ();
1613 }
1614
1615 // LordHavoc: because we don't want to load things before the video starts,
1616 // we have to delay map and game loads until AFTER video is initialized
1617 void Host_PerformSpawnServerAndLoadGame(void)
1618 {
1619         if (vid_hidden && cls.state != ca_dedicated)
1620                 return;
1621         if (sv_loadgame[0])
1622                 Host_PerformLoadGame(sv_loadgame);
1623         else if (sv_spawnmap[0])
1624                 SV_SpawnServer(sv_spawnmap);
1625         sv_loadgame[0] = 0;
1626         sv_spawnmap[0] = 0;
1627         if (sv.active && cls.state == ca_disconnected)
1628                 Cmd_ExecuteString ("connect local", src_command);
1629 }
1630
1631 //=============================================================================
1632
1633 /*
1634 ==================
1635 Host_InitCommands
1636 ==================
1637 */
1638 void Host_InitCommands (void)
1639 {
1640         Cmd_AddCommand ("status", Host_Status_f);
1641         Cmd_AddCommand ("quit", Host_Quit_f);
1642         if (gamemode == GAME_NEHAHRA)
1643         {
1644                 Cmd_AddCommand ("max", Host_God_f);
1645                 Cmd_AddCommand ("monster", Host_Notarget_f);
1646                 Cmd_AddCommand ("scrag", Host_Fly_f);
1647                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1648                 Cmd_AddCommand ("gimme", Host_Give_f);
1649         }
1650         else
1651         {
1652                 Cmd_AddCommand ("god", Host_God_f);
1653                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1654                 Cmd_AddCommand ("fly", Host_Fly_f);
1655                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1656                 Cmd_AddCommand ("give", Host_Give_f);
1657         }
1658         Cmd_AddCommand ("map", Host_Map_f);
1659         Cmd_AddCommand ("restart", Host_Restart_f);
1660         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1661         Cmd_AddCommand ("connect", Host_Connect_f);
1662         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1663         Cmd_AddCommand ("version", Host_Version_f);
1664         Cmd_AddCommand ("say", Host_Say_f);
1665         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1666         Cmd_AddCommand ("tell", Host_Tell_f);
1667         Cmd_AddCommand ("kill", Host_Kill_f);
1668         Cmd_AddCommand ("pause", Host_Pause_f);
1669         Cmd_AddCommand ("kick", Host_Kick_f);
1670         Cmd_AddCommand ("ping", Host_Ping_f);
1671         Cmd_AddCommand ("load", Host_Loadgame_f);
1672         Cmd_AddCommand ("save", Host_Savegame_f);
1673
1674         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1675         Cmd_AddCommand ("demos", Host_Demos_f);
1676         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1677
1678         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1679         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1680         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1681         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1682
1683         Cvar_RegisterVariable (&cl_name);
1684         Cmd_AddCommand ("name", Host_Name_f);
1685         Cvar_RegisterVariable (&cl_color);
1686         Cmd_AddCommand ("color", Host_Color_f);
1687         if (gamemode == GAME_NEHAHRA)
1688         {
1689                 Cvar_RegisterVariable (&cl_pmodel);
1690                 Cmd_AddCommand ("pmodel", Host_PModel_f);
1691         }
1692         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1693         Cmd_AddCommand ("spawn", Host_Spawn_f);
1694         Cmd_AddCommand ("begin", Host_Begin_f);
1695 }
1696