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