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