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