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