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