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