]> icculus.org git repositories - divverent/darkplaces.git/blob - host_cmd.c
*** empty log message ***
[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         host_client->nametime = 0;
1113
1114         // LordHavoc: moved this above the QC calls at FrikaC's request
1115         // send all current names, colors, and frag counts
1116         SZ_Clear (&host_client->message);
1117
1118         // run the entrance script
1119         if (sv.loadgame)
1120         {
1121                 // loaded games are fully initialized already
1122                 // if this is the last client to be connected, unpause
1123                 sv.paused = false;
1124
1125                 if ((f = ED_FindFunction ("RestoreGame")))
1126                 if ((RestoreGame = (func_t)(f - pr_functions)))
1127                 {
1128                         Con_DPrint("Calling RestoreGame\n");
1129                         pr_global_struct->time = sv.time;
1130                         pr_global_struct->self = EDICT_TO_PROG(sv_player);
1131                         PR_ExecuteProgram (RestoreGame, "");
1132                 }
1133         }
1134         else
1135         {
1136                 // set up the edict
1137                 ED_ClearEdict(sv_player);
1138
1139                 //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);
1140
1141                 // copy spawn parms out of the client_t
1142                 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1143                         (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
1144
1145                 // call the spawn function
1146                 pr_global_struct->time = sv.time;
1147                 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1148                 PR_ExecuteProgram (pr_global_struct->ClientConnect, "QC function ClientConnect is missing");
1149
1150                 if ((Sys_DoubleTime() - host_client->netconnection->connecttime) <= sv.time)
1151                         Sys_Printf("%s entered the game\n", host_client->name);
1152
1153                 PR_ExecuteProgram (pr_global_struct->PutClientInServer, "QC function PutClientInServer is missing");
1154         }
1155
1156
1157         // send time of update
1158         MSG_WriteByte (&host_client->message, svc_time);
1159         MSG_WriteFloat (&host_client->message, sv.time);
1160
1161         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1162         {
1163                 if (!client->active)
1164                         continue;
1165                 MSG_WriteByte (&host_client->message, svc_updatename);
1166                 MSG_WriteByte (&host_client->message, i);
1167                 MSG_WriteString (&host_client->message, client->old_name);
1168                 MSG_WriteByte (&host_client->message, svc_updatefrags);
1169                 MSG_WriteByte (&host_client->message, i);
1170                 MSG_WriteShort (&host_client->message, client->old_frags);
1171                 MSG_WriteByte (&host_client->message, svc_updatecolors);
1172                 MSG_WriteByte (&host_client->message, i);
1173                 MSG_WriteByte (&host_client->message, client->old_colors);
1174         }
1175
1176         // send all current light styles
1177         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1178         {
1179                 MSG_WriteByte (&host_client->message, svc_lightstyle);
1180                 MSG_WriteByte (&host_client->message, (char)i);
1181                 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1182         }
1183
1184         // send some stats
1185         MSG_WriteByte (&host_client->message, svc_updatestat);
1186         MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1187         MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
1188
1189         MSG_WriteByte (&host_client->message, svc_updatestat);
1190         MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1191         MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);
1192
1193         MSG_WriteByte (&host_client->message, svc_updatestat);
1194         MSG_WriteByte (&host_client->message, STAT_SECRETS);
1195         MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);
1196
1197         MSG_WriteByte (&host_client->message, svc_updatestat);
1198         MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1199         MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
1200
1201         // send a fixangle
1202         // Never send a roll angle, because savegames can catch the server
1203         // in a state where it is expecting the client to correct the angle
1204         // and it won't happen if the game was just loaded, so you wind up
1205         // with a permanent head tilt
1206         MSG_WriteByte (&host_client->message, svc_setangle);
1207         for (i=0 ; i < 2 ; i++)
1208                 MSG_WriteAngle (&host_client->message, sv_player->v->angles[i] );
1209         MSG_WriteAngle (&host_client->message, 0 );
1210
1211         SV_WriteClientdataToMessage (sv_player, &host_client->message);
1212
1213         MSG_WriteByte (&host_client->message, svc_signonnum);
1214         MSG_WriteByte (&host_client->message, 3);
1215         host_client->sendsignon = true;
1216 }
1217
1218 /*
1219 ==================
1220 Host_Begin_f
1221 ==================
1222 */
1223 void Host_Begin_f (void)
1224 {
1225         if (cmd_source == src_command)
1226         {
1227                 Con_Print("begin is not valid from the console\n");
1228                 return;
1229         }
1230
1231         host_client->spawned = true;
1232 }
1233
1234 //===========================================================================
1235
1236
1237 /*
1238 ==================
1239 Host_Kick_f
1240
1241 Kicks a user off of the server
1242 ==================
1243 */
1244 void Host_Kick_f (void)
1245 {
1246         char *who;
1247         const char *message = NULL;
1248         client_t *save;
1249         int i;
1250         qboolean byNumber = false;
1251
1252         if (cmd_source != src_command || !sv.active)
1253                 return;
1254
1255         save = host_client;
1256
1257         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1258         {
1259                 i = atof(Cmd_Argv(2)) - 1;
1260                 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1261                         return;
1262                 byNumber = true;
1263         }
1264         else
1265         {
1266                 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1267                 {
1268                         if (!host_client->active)
1269                                 continue;
1270                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1271                                 break;
1272                 }
1273         }
1274
1275         if (i < svs.maxclients)
1276         {
1277                 if (cmd_source == src_command)
1278                 {
1279                         if (cls.state == ca_dedicated)
1280                                 who = "Console";
1281                         else
1282                                 who = cl_name.string;
1283                 }
1284                 else
1285                         who = save->name;
1286
1287                 // can't kick yourself!
1288                 if (host_client == save)
1289                         return;
1290
1291                 if (Cmd_Argc() > 2)
1292                 {
1293                         message = Cmd_Args();
1294                         COM_ParseToken(&message, false);
1295                         if (byNumber)
1296                         {
1297                                 message++;                                                      // skip the #
1298                                 while (*message == ' ')                         // skip white space
1299                                         message++;
1300                                 message += strlen(Cmd_Argv(2)); // skip the number
1301                         }
1302                         while (*message && *message == ' ')
1303                                 message++;
1304                 }
1305                 if (message)
1306                         SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1307                 else
1308                         SV_ClientPrintf("Kicked by %s\n", who);
1309                 SV_DropClient (false); // kicked
1310         }
1311
1312         host_client = save;
1313 }
1314
1315 /*
1316 ===============================================================================
1317
1318 DEBUGGING TOOLS
1319
1320 ===============================================================================
1321 */
1322
1323 /*
1324 ==================
1325 Host_Give_f
1326 ==================
1327 */
1328 void Host_Give_f (void)
1329 {
1330         const char *t;
1331         int v;
1332         eval_t *val;
1333
1334         if (cmd_source == src_command)
1335         {
1336                 Cmd_ForwardToServer ();
1337                 return;
1338         }
1339
1340         if (!sv_player)
1341                 return;
1342
1343         if (!allowcheats)
1344         {
1345                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1346                 return;
1347         }
1348
1349         t = Cmd_Argv(1);
1350         v = atoi (Cmd_Argv(2));
1351
1352         switch (t[0])
1353         {
1354         case '0':
1355         case '1':
1356         case '2':
1357         case '3':
1358         case '4':
1359         case '5':
1360         case '6':
1361         case '7':
1362         case '8':
1363         case '9':
1364                 // MED 01/04/97 added hipnotic give stuff
1365                 if (gamemode == GAME_HIPNOTIC)
1366                 {
1367                         if (t[0] == '6')
1368                         {
1369                                 if (t[1] == 'a')
1370                                         sv_player->v->items = (int)sv_player->v->items | HIT_PROXIMITY_GUN;
1371                                 else
1372                                         sv_player->v->items = (int)sv_player->v->items | IT_GRENADE_LAUNCHER;
1373                         }
1374                         else if (t[0] == '9')
1375                                 sv_player->v->items = (int)sv_player->v->items | HIT_LASER_CANNON;
1376                         else if (t[0] == '0')
1377                                 sv_player->v->items = (int)sv_player->v->items | HIT_MJOLNIR;
1378                         else if (t[0] >= '2')
1379                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1380                 }
1381                 else
1382                 {
1383                         if (t[0] >= '2')
1384                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1385                 }
1386                 break;
1387
1388         case 's':
1389                 if (gamemode == GAME_ROGUE && (val = GETEDICTFIELDVALUE(sv_player, eval_ammo_shells1)))
1390                         val->_float = v;
1391
1392                 sv_player->v->ammo_shells = v;
1393                 break;
1394         case 'n':
1395                 if (gamemode == GAME_ROGUE)
1396                 {
1397                         if ((val = GETEDICTFIELDVALUE(sv_player, eval_ammo_nails1)))
1398                         {
1399                                 val->_float = v;
1400                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1401                                         sv_player->v->ammo_nails = v;
1402                         }
1403                 }
1404                 else
1405                 {
1406                         sv_player->v->ammo_nails = v;
1407                 }
1408                 break;
1409         case 'l':
1410                 if (gamemode == GAME_ROGUE)
1411                 {
1412                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_lava_nails);
1413                         if (val)
1414                         {
1415                                 val->_float = v;
1416                                 if (sv_player->v->weapon > IT_LIGHTNING)
1417                                         sv_player->v->ammo_nails = v;
1418                         }
1419                 }
1420                 break;
1421         case 'r':
1422                 if (gamemode == GAME_ROGUE)
1423                 {
1424                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_rockets1);
1425                         if (val)
1426                         {
1427                                 val->_float = v;
1428                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1429                                         sv_player->v->ammo_rockets = v;
1430                         }
1431                 }
1432                 else
1433                 {
1434                         sv_player->v->ammo_rockets = v;
1435                 }
1436                 break;
1437         case 'm':
1438                 if (gamemode == GAME_ROGUE)
1439                 {
1440                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_multi_rockets);
1441                         if (val)
1442                         {
1443                                 val->_float = v;
1444                                 if (sv_player->v->weapon > IT_LIGHTNING)
1445                                         sv_player->v->ammo_rockets = v;
1446                         }
1447                 }
1448                 break;
1449         case 'h':
1450                 sv_player->v->health = v;
1451                 break;
1452         case 'c':
1453                 if (gamemode == GAME_ROGUE)
1454                 {
1455                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_cells1);
1456                         if (val)
1457                         {
1458                                 val->_float = v;
1459                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1460                                         sv_player->v->ammo_cells = v;
1461                         }
1462                 }
1463                 else
1464                 {
1465                         sv_player->v->ammo_cells = v;
1466                 }
1467                 break;
1468         case 'p':
1469                 if (gamemode == GAME_ROGUE)
1470                 {
1471                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_plasma);
1472                         if (val)
1473                         {
1474                                 val->_float = v;
1475                                 if (sv_player->v->weapon > IT_LIGHTNING)
1476                                         sv_player->v->ammo_cells = v;
1477                         }
1478                 }
1479                 break;
1480         }
1481 }
1482
1483 edict_t *FindViewthing (void)
1484 {
1485         int             i;
1486         edict_t *e;
1487
1488         for (i=0 ; i<sv.num_edicts ; i++)
1489         {
1490                 e = EDICT_NUM(i);
1491                 if (!strcmp (PR_GetString(e->v->classname), "viewthing"))
1492                         return e;
1493         }
1494         Con_Print("No viewthing on map\n");
1495         return NULL;
1496 }
1497
1498 /*
1499 ==================
1500 Host_Viewmodel_f
1501 ==================
1502 */
1503 void Host_Viewmodel_f (void)
1504 {
1505         edict_t *e;
1506         model_t *m;
1507
1508         e = FindViewthing ();
1509         if (!e)
1510                 return;
1511
1512         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1513         if (!m)
1514         {
1515                 Con_Printf("Can't load %s\n", Cmd_Argv(1));
1516                 return;
1517         }
1518
1519         e->v->frame = 0;
1520         cl.model_precache[(int)e->v->modelindex] = m;
1521 }
1522
1523 /*
1524 ==================
1525 Host_Viewframe_f
1526 ==================
1527 */
1528 void Host_Viewframe_f (void)
1529 {
1530         edict_t *e;
1531         int             f;
1532         model_t *m;
1533
1534         e = FindViewthing ();
1535         if (!e)
1536                 return;
1537         m = cl.model_precache[(int)e->v->modelindex];
1538
1539         f = atoi(Cmd_Argv(1));
1540         if (f >= m->numframes)
1541                 f = m->numframes-1;
1542
1543         e->v->frame = f;
1544 }
1545
1546
1547 void PrintFrameName (model_t *m, int frame)
1548 {
1549         if (m->animscenes)
1550                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1551         else
1552                 Con_Printf("frame %i\n", frame);
1553 }
1554
1555 /*
1556 ==================
1557 Host_Viewnext_f
1558 ==================
1559 */
1560 void Host_Viewnext_f (void)
1561 {
1562         edict_t *e;
1563         model_t *m;
1564
1565         e = FindViewthing ();
1566         if (!e)
1567                 return;
1568         m = cl.model_precache[(int)e->v->modelindex];
1569
1570         e->v->frame = e->v->frame + 1;
1571         if (e->v->frame >= m->numframes)
1572                 e->v->frame = m->numframes - 1;
1573
1574         PrintFrameName (m, e->v->frame);
1575 }
1576
1577 /*
1578 ==================
1579 Host_Viewprev_f
1580 ==================
1581 */
1582 void Host_Viewprev_f (void)
1583 {
1584         edict_t *e;
1585         model_t *m;
1586
1587         e = FindViewthing ();
1588         if (!e)
1589                 return;
1590
1591         m = cl.model_precache[(int)e->v->modelindex];
1592
1593         e->v->frame = e->v->frame - 1;
1594         if (e->v->frame < 0)
1595                 e->v->frame = 0;
1596
1597         PrintFrameName (m, e->v->frame);
1598 }
1599
1600 /*
1601 ===============================================================================
1602
1603 DEMO LOOP CONTROL
1604
1605 ===============================================================================
1606 */
1607
1608
1609 /*
1610 ==================
1611 Host_Startdemos_f
1612 ==================
1613 */
1614 void Host_Startdemos_f (void)
1615 {
1616         int             i, c;
1617
1618         if (cls.state == ca_dedicated || COM_CheckParm("-listen"))
1619         {
1620                 if (!sv.active)
1621                 {
1622                         if (gamemode == GAME_TRANSFUSION)
1623                                 Cbuf_AddText ("map bb1\n");
1624                         else
1625                                 Cbuf_AddText ("map start\n");
1626                 }
1627                 return;
1628         }
1629
1630         c = Cmd_Argc() - 1;
1631         if (c > MAX_DEMOS)
1632         {
1633                 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
1634                 c = MAX_DEMOS;
1635         }
1636         Con_DPrintf("%i demo(s) in loop\n", c);
1637
1638         for (i=1 ; i<c+1 ; i++)
1639                 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
1640
1641         // LordHavoc: clear the remaining slots
1642         for (;i <= MAX_DEMOS;i++)
1643                 cls.demos[i-1][0] = 0;
1644
1645         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1646         {
1647                 cls.demonum = 0;
1648                 CL_NextDemo ();
1649         }
1650         else
1651                 cls.demonum = -1;
1652 }
1653
1654
1655 /*
1656 ==================
1657 Host_Demos_f
1658
1659 Return to looping demos
1660 ==================
1661 */
1662 void Host_Demos_f (void)
1663 {
1664         if (cls.state == ca_dedicated)
1665                 return;
1666         if (cls.demonum == -1)
1667                 cls.demonum = 1;
1668         CL_Disconnect_f ();
1669         CL_NextDemo ();
1670 }
1671
1672 /*
1673 ==================
1674 Host_Stopdemo_f
1675
1676 Return to looping demos
1677 ==================
1678 */
1679 void Host_Stopdemo_f (void)
1680 {
1681         if (!cls.demoplayback)
1682                 return;
1683         CL_Disconnect ();
1684         Host_ShutdownServer (false);
1685 }
1686
1687 static void MaxPlayers_f(void)
1688 {
1689         int n;
1690
1691         if (Cmd_Argc() != 2)
1692         {
1693                 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
1694                 return;
1695         }
1696
1697         if (sv.active)
1698         {
1699                 Con_Print("maxplayers can not be changed while a server is running.\n");
1700                 return;
1701         }
1702
1703         n = atoi(Cmd_Argv(1));
1704         n = bound(1, n, MAX_SCOREBOARD);
1705         Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1706
1707         if (svs.clients)
1708                 Mem_Free(svs.clients);
1709         svs.maxclients = n;
1710         svs.clients = Mem_Alloc(sv_clients_mempool, sizeof(client_t) * svs.maxclients);
1711         if (n == 1)
1712                 Cvar_Set ("deathmatch", "0");
1713         else
1714                 Cvar_Set ("deathmatch", "1");
1715 }
1716
1717 //=============================================================================
1718
1719 /*
1720 ==================
1721 Host_InitCommands
1722 ==================
1723 */
1724 void Host_InitCommands (void)
1725 {
1726         Cmd_AddCommand ("status", Host_Status_f);
1727         Cmd_AddCommand ("quit", Host_Quit_f);
1728         if (gamemode == GAME_NEHAHRA)
1729         {
1730                 Cmd_AddCommand ("max", Host_God_f);
1731                 Cmd_AddCommand ("monster", Host_Notarget_f);
1732                 Cmd_AddCommand ("scrag", Host_Fly_f);
1733                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1734                 Cmd_AddCommand ("gimme", Host_Give_f);
1735         }
1736         else
1737         {
1738                 Cmd_AddCommand ("god", Host_God_f);
1739                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1740                 Cmd_AddCommand ("fly", Host_Fly_f);
1741                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1742                 Cmd_AddCommand ("give", Host_Give_f);
1743         }
1744         Cmd_AddCommand ("map", Host_Map_f);
1745         Cmd_AddCommand ("restart", Host_Restart_f);
1746         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1747         Cmd_AddCommand ("connect", Host_Connect_f);
1748         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1749         Cmd_AddCommand ("version", Host_Version_f);
1750         Cmd_AddCommand ("say", Host_Say_f);
1751         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1752         Cmd_AddCommand ("tell", Host_Tell_f);
1753         Cmd_AddCommand ("kill", Host_Kill_f);
1754         Cmd_AddCommand ("pause", Host_Pause_f);
1755         Cmd_AddCommand ("kick", Host_Kick_f);
1756         Cmd_AddCommand ("ping", Host_Ping_f);
1757         Cmd_AddCommand ("load", Host_Loadgame_f);
1758         Cmd_AddCommand ("save", Host_Savegame_f);
1759
1760         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1761         Cmd_AddCommand ("demos", Host_Demos_f);
1762         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1763
1764         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1765         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1766         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1767         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1768
1769         Cvar_RegisterVariable (&cl_name);
1770         Cmd_AddCommand ("name", Host_Name_f);
1771         Cvar_RegisterVariable (&cl_color);
1772         Cmd_AddCommand ("color", Host_Color_f);
1773         Cvar_RegisterVariable (&cl_rate);
1774         Cmd_AddCommand ("rate", Host_Rate_f);
1775         Cvar_RegisterVariable (&sv_maxrate);
1776         if (gamemode == GAME_NEHAHRA)
1777         {
1778                 Cvar_RegisterVariable (&cl_pmodel);
1779                 Cmd_AddCommand ("pmodel", Host_PModel_f);
1780         }
1781         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1782         Cmd_AddCommand ("spawn", Host_Spawn_f);
1783         Cmd_AddCommand ("begin", Host_Begin_f);
1784         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
1785
1786         Cvar_RegisterVariable(&sv_cheats);
1787 }
1788