]> icculus.org git repositories - divverent/darkplaces.git/blob - host_cmd.c
PROTOCOL_DARKPLACES5
[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         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         if (sv.protocol == PROTOCOL_DARKPLACES5)
1220         {
1221                 MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[0]);
1222                 MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[1]);
1223                 MSG_WriteAngle16i (&host_client->message, 0);
1224         }
1225         else
1226         {
1227                 MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[0]);
1228                 MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[1]);
1229                 MSG_WriteAngle8i (&host_client->message, 0);
1230         }
1231
1232         SV_WriteClientdataToMessage (sv_player, &host_client->message);
1233
1234         MSG_WriteByte (&host_client->message, svc_signonnum);
1235         MSG_WriteByte (&host_client->message, 3);
1236         host_client->sendsignon = true;
1237 }
1238
1239 /*
1240 ==================
1241 Host_Begin_f
1242 ==================
1243 */
1244 void Host_Begin_f (void)
1245 {
1246         if (cmd_source == src_command)
1247         {
1248                 Con_Print("begin is not valid from the console\n");
1249                 return;
1250         }
1251
1252         host_client->spawned = true;
1253 }
1254
1255 //===========================================================================
1256
1257
1258 /*
1259 ==================
1260 Host_Kick_f
1261
1262 Kicks a user off of the server
1263 ==================
1264 */
1265 void Host_Kick_f (void)
1266 {
1267         char *who;
1268         const char *message = NULL;
1269         client_t *save;
1270         int i;
1271         qboolean byNumber = false;
1272
1273         if (cmd_source != src_command || !sv.active)
1274                 return;
1275
1276         save = host_client;
1277
1278         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1279         {
1280                 i = atof(Cmd_Argv(2)) - 1;
1281                 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1282                         return;
1283                 byNumber = true;
1284         }
1285         else
1286         {
1287                 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1288                 {
1289                         if (!host_client->active)
1290                                 continue;
1291                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1292                                 break;
1293                 }
1294         }
1295
1296         if (i < svs.maxclients)
1297         {
1298                 if (cmd_source == src_command)
1299                 {
1300                         if (cls.state == ca_dedicated)
1301                                 who = "Console";
1302                         else
1303                                 who = cl_name.string;
1304                 }
1305                 else
1306                         who = save->name;
1307
1308                 // can't kick yourself!
1309                 if (host_client == save)
1310                         return;
1311
1312                 if (Cmd_Argc() > 2)
1313                 {
1314                         message = Cmd_Args();
1315                         COM_ParseToken(&message, false);
1316                         if (byNumber)
1317                         {
1318                                 message++;                                                      // skip the #
1319                                 while (*message == ' ')                         // skip white space
1320                                         message++;
1321                                 message += strlen(Cmd_Argv(2)); // skip the number
1322                         }
1323                         while (*message && *message == ' ')
1324                                 message++;
1325                 }
1326                 if (message)
1327                         SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1328                 else
1329                         SV_ClientPrintf("Kicked by %s\n", who);
1330                 SV_DropClient (false); // kicked
1331         }
1332
1333         host_client = save;
1334 }
1335
1336 /*
1337 ===============================================================================
1338
1339 DEBUGGING TOOLS
1340
1341 ===============================================================================
1342 */
1343
1344 /*
1345 ==================
1346 Host_Give_f
1347 ==================
1348 */
1349 void Host_Give_f (void)
1350 {
1351         const char *t;
1352         int v;
1353         eval_t *val;
1354
1355         if (cmd_source == src_command)
1356         {
1357                 Cmd_ForwardToServer ();
1358                 return;
1359         }
1360
1361         if (!sv_player)
1362                 return;
1363
1364         if (!allowcheats)
1365         {
1366                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1367                 return;
1368         }
1369
1370         t = Cmd_Argv(1);
1371         v = atoi (Cmd_Argv(2));
1372
1373         switch (t[0])
1374         {
1375         case '0':
1376         case '1':
1377         case '2':
1378         case '3':
1379         case '4':
1380         case '5':
1381         case '6':
1382         case '7':
1383         case '8':
1384         case '9':
1385                 // MED 01/04/97 added hipnotic give stuff
1386                 if (gamemode == GAME_HIPNOTIC)
1387                 {
1388                         if (t[0] == '6')
1389                         {
1390                                 if (t[1] == 'a')
1391                                         sv_player->v->items = (int)sv_player->v->items | HIT_PROXIMITY_GUN;
1392                                 else
1393                                         sv_player->v->items = (int)sv_player->v->items | IT_GRENADE_LAUNCHER;
1394                         }
1395                         else if (t[0] == '9')
1396                                 sv_player->v->items = (int)sv_player->v->items | HIT_LASER_CANNON;
1397                         else if (t[0] == '0')
1398                                 sv_player->v->items = (int)sv_player->v->items | HIT_MJOLNIR;
1399                         else if (t[0] >= '2')
1400                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1401                 }
1402                 else
1403                 {
1404                         if (t[0] >= '2')
1405                                 sv_player->v->items = (int)sv_player->v->items | (IT_SHOTGUN << (t[0] - '2'));
1406                 }
1407                 break;
1408
1409         case 's':
1410                 if (gamemode == GAME_ROGUE && (val = GETEDICTFIELDVALUE(sv_player, eval_ammo_shells1)))
1411                         val->_float = v;
1412
1413                 sv_player->v->ammo_shells = v;
1414                 break;
1415         case 'n':
1416                 if (gamemode == GAME_ROGUE)
1417                 {
1418                         if ((val = GETEDICTFIELDVALUE(sv_player, eval_ammo_nails1)))
1419                         {
1420                                 val->_float = v;
1421                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1422                                         sv_player->v->ammo_nails = v;
1423                         }
1424                 }
1425                 else
1426                 {
1427                         sv_player->v->ammo_nails = v;
1428                 }
1429                 break;
1430         case 'l':
1431                 if (gamemode == GAME_ROGUE)
1432                 {
1433                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_lava_nails);
1434                         if (val)
1435                         {
1436                                 val->_float = v;
1437                                 if (sv_player->v->weapon > IT_LIGHTNING)
1438                                         sv_player->v->ammo_nails = v;
1439                         }
1440                 }
1441                 break;
1442         case 'r':
1443                 if (gamemode == GAME_ROGUE)
1444                 {
1445                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_rockets1);
1446                         if (val)
1447                         {
1448                                 val->_float = v;
1449                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1450                                         sv_player->v->ammo_rockets = v;
1451                         }
1452                 }
1453                 else
1454                 {
1455                         sv_player->v->ammo_rockets = v;
1456                 }
1457                 break;
1458         case 'm':
1459                 if (gamemode == GAME_ROGUE)
1460                 {
1461                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_multi_rockets);
1462                         if (val)
1463                         {
1464                                 val->_float = v;
1465                                 if (sv_player->v->weapon > IT_LIGHTNING)
1466                                         sv_player->v->ammo_rockets = v;
1467                         }
1468                 }
1469                 break;
1470         case 'h':
1471                 sv_player->v->health = v;
1472                 break;
1473         case 'c':
1474                 if (gamemode == GAME_ROGUE)
1475                 {
1476                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_cells1);
1477                         if (val)
1478                         {
1479                                 val->_float = v;
1480                                 if (sv_player->v->weapon <= IT_LIGHTNING)
1481                                         sv_player->v->ammo_cells = v;
1482                         }
1483                 }
1484                 else
1485                 {
1486                         sv_player->v->ammo_cells = v;
1487                 }
1488                 break;
1489         case 'p':
1490                 if (gamemode == GAME_ROGUE)
1491                 {
1492                         val = GETEDICTFIELDVALUE(sv_player, eval_ammo_plasma);
1493                         if (val)
1494                         {
1495                                 val->_float = v;
1496                                 if (sv_player->v->weapon > IT_LIGHTNING)
1497                                         sv_player->v->ammo_cells = v;
1498                         }
1499                 }
1500                 break;
1501         }
1502 }
1503
1504 edict_t *FindViewthing (void)
1505 {
1506         int             i;
1507         edict_t *e;
1508
1509         for (i=0 ; i<sv.num_edicts ; i++)
1510         {
1511                 e = EDICT_NUM(i);
1512                 if (!strcmp (PR_GetString(e->v->classname), "viewthing"))
1513                         return e;
1514         }
1515         Con_Print("No viewthing on map\n");
1516         return NULL;
1517 }
1518
1519 /*
1520 ==================
1521 Host_Viewmodel_f
1522 ==================
1523 */
1524 void Host_Viewmodel_f (void)
1525 {
1526         edict_t *e;
1527         model_t *m;
1528
1529         e = FindViewthing ();
1530         if (!e)
1531                 return;
1532
1533         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1534         if (!m)
1535         {
1536                 Con_Printf("Can't load %s\n", Cmd_Argv(1));
1537                 return;
1538         }
1539
1540         e->v->frame = 0;
1541         cl.model_precache[(int)e->v->modelindex] = m;
1542 }
1543
1544 /*
1545 ==================
1546 Host_Viewframe_f
1547 ==================
1548 */
1549 void Host_Viewframe_f (void)
1550 {
1551         edict_t *e;
1552         int             f;
1553         model_t *m;
1554
1555         e = FindViewthing ();
1556         if (!e)
1557                 return;
1558         m = cl.model_precache[(int)e->v->modelindex];
1559
1560         f = atoi(Cmd_Argv(1));
1561         if (f >= m->numframes)
1562                 f = m->numframes-1;
1563
1564         e->v->frame = f;
1565 }
1566
1567
1568 void PrintFrameName (model_t *m, int frame)
1569 {
1570         if (m->animscenes)
1571                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1572         else
1573                 Con_Printf("frame %i\n", frame);
1574 }
1575
1576 /*
1577 ==================
1578 Host_Viewnext_f
1579 ==================
1580 */
1581 void Host_Viewnext_f (void)
1582 {
1583         edict_t *e;
1584         model_t *m;
1585
1586         e = FindViewthing ();
1587         if (!e)
1588                 return;
1589         m = cl.model_precache[(int)e->v->modelindex];
1590
1591         e->v->frame = e->v->frame + 1;
1592         if (e->v->frame >= m->numframes)
1593                 e->v->frame = m->numframes - 1;
1594
1595         PrintFrameName (m, e->v->frame);
1596 }
1597
1598 /*
1599 ==================
1600 Host_Viewprev_f
1601 ==================
1602 */
1603 void Host_Viewprev_f (void)
1604 {
1605         edict_t *e;
1606         model_t *m;
1607
1608         e = FindViewthing ();
1609         if (!e)
1610                 return;
1611
1612         m = cl.model_precache[(int)e->v->modelindex];
1613
1614         e->v->frame = e->v->frame - 1;
1615         if (e->v->frame < 0)
1616                 e->v->frame = 0;
1617
1618         PrintFrameName (m, e->v->frame);
1619 }
1620
1621 /*
1622 ===============================================================================
1623
1624 DEMO LOOP CONTROL
1625
1626 ===============================================================================
1627 */
1628
1629
1630 /*
1631 ==================
1632 Host_Startdemos_f
1633 ==================
1634 */
1635 void Host_Startdemos_f (void)
1636 {
1637         int             i, c;
1638
1639         if (cls.state == ca_dedicated || COM_CheckParm("-listen"))
1640         {
1641                 if (!sv.active)
1642                 {
1643                         if (gamemode == GAME_TRANSFUSION)
1644                                 Cbuf_AddText ("map bb1\n");
1645                         else
1646                                 Cbuf_AddText ("map start\n");
1647                 }
1648                 return;
1649         }
1650
1651         c = Cmd_Argc() - 1;
1652         if (c > MAX_DEMOS)
1653         {
1654                 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
1655                 c = MAX_DEMOS;
1656         }
1657         Con_DPrintf("%i demo(s) in loop\n", c);
1658
1659         for (i=1 ; i<c+1 ; i++)
1660                 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
1661
1662         // LordHavoc: clear the remaining slots
1663         for (;i <= MAX_DEMOS;i++)
1664                 cls.demos[i-1][0] = 0;
1665
1666         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1667         {
1668                 cls.demonum = 0;
1669                 CL_NextDemo ();
1670         }
1671         else
1672                 cls.demonum = -1;
1673 }
1674
1675
1676 /*
1677 ==================
1678 Host_Demos_f
1679
1680 Return to looping demos
1681 ==================
1682 */
1683 void Host_Demos_f (void)
1684 {
1685         if (cls.state == ca_dedicated)
1686                 return;
1687         if (cls.demonum == -1)
1688                 cls.demonum = 1;
1689         CL_Disconnect_f ();
1690         CL_NextDemo ();
1691 }
1692
1693 /*
1694 ==================
1695 Host_Stopdemo_f
1696
1697 Return to looping demos
1698 ==================
1699 */
1700 void Host_Stopdemo_f (void)
1701 {
1702         if (!cls.demoplayback)
1703                 return;
1704         CL_Disconnect ();
1705         Host_ShutdownServer (false);
1706 }
1707
1708 static void MaxPlayers_f(void)
1709 {
1710         int n;
1711
1712         if (Cmd_Argc() != 2)
1713         {
1714                 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
1715                 return;
1716         }
1717
1718         if (sv.active)
1719         {
1720                 Con_Print("maxplayers can not be changed while a server is running.\n");
1721                 return;
1722         }
1723
1724         n = atoi(Cmd_Argv(1));
1725         n = bound(1, n, MAX_SCOREBOARD);
1726         Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1727
1728         if (svs.clients)
1729                 Mem_Free(svs.clients);
1730         svs.maxclients = n;
1731         svs.clients = Mem_Alloc(sv_clients_mempool, sizeof(client_t) * svs.maxclients);
1732         if (n == 1)
1733                 Cvar_Set ("deathmatch", "0");
1734         else
1735                 Cvar_Set ("deathmatch", "1");
1736 }
1737
1738 //=============================================================================
1739
1740 /*
1741 ==================
1742 Host_InitCommands
1743 ==================
1744 */
1745 void Host_InitCommands (void)
1746 {
1747         Cmd_AddCommand ("status", Host_Status_f);
1748         Cmd_AddCommand ("quit", Host_Quit_f);
1749         if (gamemode == GAME_NEHAHRA)
1750         {
1751                 Cmd_AddCommand ("max", Host_God_f);
1752                 Cmd_AddCommand ("monster", Host_Notarget_f);
1753                 Cmd_AddCommand ("scrag", Host_Fly_f);
1754                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1755                 Cmd_AddCommand ("gimme", Host_Give_f);
1756         }
1757         else
1758         {
1759                 Cmd_AddCommand ("god", Host_God_f);
1760                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1761                 Cmd_AddCommand ("fly", Host_Fly_f);
1762                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1763                 Cmd_AddCommand ("give", Host_Give_f);
1764         }
1765         Cmd_AddCommand ("map", Host_Map_f);
1766         Cmd_AddCommand ("restart", Host_Restart_f);
1767         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1768         Cmd_AddCommand ("connect", Host_Connect_f);
1769         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1770         Cmd_AddCommand ("version", Host_Version_f);
1771         Cmd_AddCommand ("say", Host_Say_f);
1772         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1773         Cmd_AddCommand ("tell", Host_Tell_f);
1774         Cmd_AddCommand ("kill", Host_Kill_f);
1775         Cmd_AddCommand ("pause", Host_Pause_f);
1776         Cmd_AddCommand ("kick", Host_Kick_f);
1777         Cmd_AddCommand ("ping", Host_Ping_f);
1778         Cmd_AddCommand ("load", Host_Loadgame_f);
1779         Cmd_AddCommand ("save", Host_Savegame_f);
1780
1781         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1782         Cmd_AddCommand ("demos", Host_Demos_f);
1783         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1784
1785         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1786         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1787         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1788         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1789
1790         Cvar_RegisterVariable (&cl_name);
1791         Cmd_AddCommand ("name", Host_Name_f);
1792         Cvar_RegisterVariable (&cl_color);
1793         Cmd_AddCommand ("color", Host_Color_f);
1794         Cvar_RegisterVariable (&cl_rate);
1795         Cmd_AddCommand ("rate", Host_Rate_f);
1796         if (gamemode == GAME_NEHAHRA)
1797         {
1798                 Cvar_RegisterVariable (&cl_pmodel);
1799                 Cmd_AddCommand ("pmodel", Host_PModel_f);
1800         }
1801         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1802         Cmd_AddCommand ("spawn", Host_Spawn_f);
1803         Cmd_AddCommand ("begin", Host_Begin_f);
1804         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
1805
1806         Cvar_RegisterVariable(&sv_cheats);
1807 }
1808