]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - host_cmd.c
use latest ping from client struct rather than averaging ping_times
[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                 SV_ClientPrintf("%4i %s\n", (int)(client->ping*1000), client->name);
228         }
229 }
230
231 /*
232 ===============================================================================
233
234 SERVER TRANSITIONS
235
236 ===============================================================================
237 */
238
239 /*
240 ======================
241 Host_Map_f
242
243 handle a
244 map <servername>
245 command from the console.  Active clients are kicked off.
246 ======================
247 */
248 void Host_Map_f (void)
249 {
250         char level[MAX_QPATH];
251
252         if (Cmd_Argc() != 2)
253         {
254                 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
255                 return;
256         }
257
258         if (cmd_source != src_command)
259                 return;
260
261         cls.demonum = -1;               // stop demo loop in case this fails
262
263         CL_Disconnect ();
264         Host_ShutdownServer(false);
265
266         // remove console or menu
267         key_dest = key_game;
268         key_consoleactive = 0;
269
270         svs.serverflags = 0;                    // haven't completed an episode yet
271         allowcheats = sv_cheats.integer != 0;
272         strcpy(level, Cmd_Argv(1));
273         SV_SpawnServer(level);
274         if (sv.active && cls.state == ca_disconnected)
275         {
276                 SV_VM_Begin();
277                 CL_EstablishConnection("local:1");
278                 SV_VM_End();
279         }
280 }
281
282 /*
283 ==================
284 Host_Changelevel_f
285
286 Goes to a new map, taking all clients along
287 ==================
288 */
289 void Host_Changelevel_f (void)
290 {
291         char level[MAX_QPATH];
292
293         if (Cmd_Argc() != 2)
294         {
295                 Con_Print("changelevel <levelname> : continue game on a new level\n");
296                 return;
297         }
298         if (!sv.active || cls.demoplayback)
299         {
300                 Con_Print("Only the server may changelevel\n");
301                 return;
302         }
303         if (cmd_source != src_command)
304                 return;
305
306         // remove console or menu
307         key_dest = key_game;
308         key_consoleactive = 0;
309
310         SV_VM_Begin();
311         SV_SaveSpawnparms ();
312         SV_VM_End();
313         allowcheats = sv_cheats.integer != 0;
314         strcpy(level, Cmd_Argv(1));
315         SV_SpawnServer(level);
316         if (sv.active && cls.state == ca_disconnected)
317         {
318                 SV_VM_Begin();
319                 CL_EstablishConnection("local:1");
320                 SV_VM_End();
321         }
322 }
323
324 /*
325 ==================
326 Host_Restart_f
327
328 Restarts the current server for a dead player
329 ==================
330 */
331 void Host_Restart_f (void)
332 {
333         char mapname[MAX_QPATH];
334
335         if (Cmd_Argc() != 1)
336         {
337                 Con_Print("restart : restart current level\n");
338                 return;
339         }
340         if (!sv.active || cls.demoplayback)
341         {
342                 Con_Print("Only the server may restart\n");
343                 return;
344         }
345         if (cmd_source != src_command)
346                 return;
347
348         // remove console or menu
349         key_dest = key_game;
350         key_consoleactive = 0;
351
352         allowcheats = sv_cheats.integer != 0;
353         strcpy(mapname, sv.name);
354         SV_SpawnServer(mapname);
355         if (sv.active && cls.state == ca_disconnected)
356         {
357                 SV_VM_Begin();
358                 CL_EstablishConnection("local:1");
359                 SV_VM_End();
360         }
361 }
362
363 /*
364 ==================
365 Host_Reconnect_f
366
367 This command causes the client to wait for the signon messages again.
368 This is sent just before a server changes levels
369 ==================
370 */
371 void Host_Reconnect_f (void)
372 {
373         if (Cmd_Argc() != 1)
374         {
375                 Con_Print("reconnect : wait for signon messages again\n");
376                 return;
377         }
378         if (!cls.signon)
379         {
380                 //Con_Print("reconnect: no signon, ignoring reconnect\n");
381                 return;
382         }
383         cls.signon = 0;         // need new connection messages
384 }
385
386 /*
387 =====================
388 Host_Connect_f
389
390 User command to connect to server
391 =====================
392 */
393 void Host_Connect_f (void)
394 {
395         if (Cmd_Argc() != 2)
396         {
397                 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
398                 return;
399         }
400         if( sv.active ) {
401                 SV_VM_Begin();
402                 CL_EstablishConnection(Cmd_Argv(1));
403                 SV_VM_End();
404         } else {
405                 CL_EstablishConnection(Cmd_Argv(1));
406         }
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         if (cls.state == ca_dedicated)
951                 Con_Print(&text[1]);
952 }
953
954
955 void Host_Say_f(void)
956 {
957         Host_Say(false);
958 }
959
960
961 void Host_Say_Team_f(void)
962 {
963         Host_Say(true);
964 }
965
966
967 void Host_Tell_f(void)
968 {
969         client_t *save;
970         int j;
971         const char *p1, *p2;
972         char text[1024]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
973         qboolean fromServer = false;
974
975         if (cmd_source == src_command)
976         {
977                 if (cls.state == ca_dedicated)
978                         fromServer = true;
979                 else
980                 {
981                         Cmd_ForwardToServer ();
982                         return;
983                 }
984         }
985
986         if (Cmd_Argc () < 3)
987                 return;
988
989         if (!fromServer)
990                 sprintf (text, "%s: ", host_client->name);
991         else
992                 sprintf (text, "<%s> ", hostname.string);
993
994         p1 = Cmd_Args();
995         p2 = p1 + strlen(p1);
996         // remove the target name
997         while (p1 < p2 && *p1 != ' ')
998                 p1++;
999         while (p1 < p2 && *p1 == ' ')
1000                 p1++;
1001         // remove trailing newlines
1002         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1003                 p2--;
1004         // remove quotes if present
1005         if (*p1 == '"')
1006         {
1007                 p1++;
1008                 if (p2[-1] == '"')
1009                         p2--;
1010                 else if (fromServer)
1011                         Con_Print("Host_Tell: missing end quote\n");
1012                 else
1013                         SV_ClientPrint("Host_Tell: missing end quote\n");
1014         }
1015         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1016                 p2--;
1017         for (j = strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1018                 text[j++] = *p1++;
1019         text[j++] = '\n';
1020         text[j++] = 0;
1021
1022         save = host_client;
1023         for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1024                 if (host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
1025                         SV_ClientPrint(text);
1026         host_client = save;
1027 }
1028
1029
1030 /*
1031 ==================
1032 Host_Color_f
1033 ==================
1034 */
1035 cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
1036 void Host_Color_f(void)
1037 {
1038         int             top, bottom;
1039         int             playercolor;
1040         mfunction_t *f;
1041         func_t  SV_ChangeTeam;
1042
1043         if (Cmd_Argc() == 1)
1044         {
1045                 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1046                 Con_Print("color <0-15> [0-15]\n");
1047                 return;
1048         }
1049
1050         if (Cmd_Argc() == 2)
1051                 top = bottom = atoi(Cmd_Argv(1));
1052         else
1053         {
1054                 top = atoi(Cmd_Argv(1));
1055                 bottom = atoi(Cmd_Argv(2));
1056         }
1057
1058         top &= 15;
1059         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
1060         if (top > 15)
1061                 top = 15;
1062         bottom &= 15;
1063         // LordHavoc: allow skin colormaps 14 and 15 (was 13)
1064         if (bottom > 15)
1065                 bottom = 15;
1066
1067         playercolor = top*16 + bottom;
1068
1069         if (cmd_source == src_command)
1070         {
1071                 Cvar_SetValue ("_cl_color", playercolor);
1072                 if (cls.state == ca_connected)
1073                         Cmd_ForwardToServer ();
1074                 return;
1075         }
1076
1077         if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions)))
1078         {
1079                 Con_DPrint("Calling SV_ChangeTeam\n");
1080                 prog->globals.server->time = sv.time;
1081                 prog->globals.generic[OFS_PARM0] = playercolor;
1082                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1083                 PRVM_ExecuteProgram (SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1084         }
1085         else
1086         {
1087                 prvm_eval_t *val;
1088                 if (host_client->edict)
1089                 {
1090                         if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1091                                 val->_float = playercolor;
1092                         host_client->edict->fields.server->team = bottom + 1;
1093                 }
1094                 host_client->colors = playercolor;
1095                 if (host_client->old_colors != host_client->colors)
1096                 {
1097                         host_client->old_colors = host_client->colors;
1098                         // send notification to all clients
1099                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1100                         MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1101                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1102                 }
1103         }
1104 }
1105
1106 cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000"};
1107 void Host_Rate_f(void)
1108 {
1109         int rate;
1110
1111         if (Cmd_Argc() != 2)
1112         {
1113                 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1114                 Con_Print("rate <500-25000>\n");
1115                 return;
1116         }
1117
1118         rate = atoi(Cmd_Argv(1));
1119
1120         if (cmd_source == src_command)
1121         {
1122                 Cvar_SetValue ("_cl_rate", bound(NET_MINRATE, rate, NET_MAXRATE));
1123                 if (cls.state == ca_connected)
1124                         Cmd_ForwardToServer ();
1125                 return;
1126         }
1127
1128         host_client->rate = rate;
1129 }
1130
1131 /*
1132 ==================
1133 Host_Kill_f
1134 ==================
1135 */
1136 void Host_Kill_f (void)
1137 {
1138         if (cmd_source == src_command)
1139         {
1140                 Cmd_ForwardToServer ();
1141                 return;
1142         }
1143
1144         if (host_client->edict->fields.server->health <= 0)
1145         {
1146                 SV_ClientPrint("Can't suicide -- already dead!\n");
1147                 return;
1148         }
1149
1150         prog->globals.server->time = sv.time;
1151         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1152         PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1153 }
1154
1155
1156 /*
1157 ==================
1158 Host_Pause_f
1159 ==================
1160 */
1161 void Host_Pause_f (void)
1162 {
1163
1164         if (cmd_source == src_command)
1165         {
1166                 Cmd_ForwardToServer ();
1167                 return;
1168         }
1169         if (!pausable.integer)
1170                 SV_ClientPrint("Pause not allowed.\n");
1171         else
1172         {
1173                 sv.paused ^= 1;
1174                 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1175                 // send notification to all clients
1176                 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1177                 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1178         }
1179 }
1180
1181 /*
1182 ======================
1183 Host_PModel_f
1184 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1185 ======================
1186 */
1187 cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
1188 static void Host_PModel_f (void)
1189 {
1190         int i;
1191         prvm_eval_t *val;
1192
1193         if (Cmd_Argc () == 1)
1194         {
1195                 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1196                 return;
1197         }
1198         i = atoi(Cmd_Argv(1));
1199
1200         if (cmd_source == src_command)
1201         {
1202                 if (cl_pmodel.integer == i)
1203                         return;
1204                 Cvar_SetValue ("_cl_pmodel", i);
1205                 if (cls.state == ca_connected)
1206                         Cmd_ForwardToServer ();
1207                 return;
1208         }
1209
1210         if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
1211                 val->_float = i;
1212 }
1213
1214 //===========================================================================
1215
1216
1217 /*
1218 ==================
1219 Host_PreSpawn_f
1220 ==================
1221 */
1222 void Host_PreSpawn_f (void)
1223 {
1224         if (cmd_source == src_command)
1225         {
1226                 Con_Print("prespawn is not valid from the console\n");
1227                 return;
1228         }
1229
1230         if (host_client->spawned)
1231         {
1232                 Con_Print("prespawn not valid -- already spawned\n");
1233                 return;
1234         }
1235
1236         SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
1237         MSG_WriteByte (&host_client->message, svc_signonnum);
1238         MSG_WriteByte (&host_client->message, 2);
1239         host_client->sendsignon = true;
1240
1241         // reset the name change timer because the client will send name soon
1242         host_client->nametime = 0;
1243 }
1244
1245 /*
1246 ==================
1247 Host_Spawn_f
1248 ==================
1249 */
1250 void Host_Spawn_f (void)
1251 {
1252         int i;
1253         client_t *client;
1254         func_t RestoreGame;
1255         mfunction_t *f;
1256         int stats[MAX_CL_STATS];
1257
1258         if (cmd_source == src_command)
1259         {
1260                 Con_Print("spawn is not valid from the console\n");
1261                 return;
1262         }
1263
1264         if (host_client->spawned)
1265         {
1266                 Con_Print("Spawn not valid -- already spawned\n");
1267                 return;
1268         }
1269
1270         // reset name change timer again because they might want to change name
1271         // again in the first 5 seconds after connecting
1272         host_client->nametime = 0;
1273
1274         // LordHavoc: moved this above the QC calls at FrikaC's request
1275         // send all current names, colors, and frag counts
1276         SZ_Clear (&host_client->message);
1277
1278         // run the entrance script
1279         if (sv.loadgame)
1280         {
1281                 // loaded games are fully initialized already
1282                 // if this is the last client to be connected, unpause
1283                 sv.paused = false;
1284
1285                 if ((f = PRVM_ED_FindFunction ("RestoreGame")))
1286                 if ((RestoreGame = (func_t)(f - prog->functions)))
1287                 {
1288                         Con_DPrint("Calling RestoreGame\n");
1289                         prog->globals.server->time = sv.time;
1290                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1291                         PRVM_ExecuteProgram (RestoreGame, "QC function RestoreGame is missing");
1292                 }
1293         }
1294         else
1295         {
1296                 // set up the edict
1297                 PRVM_ED_ClearEdict(host_client->edict);
1298
1299                 //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);
1300
1301                 // copy spawn parms out of the client_t
1302                 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1303                         (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1304
1305                 // call the spawn function
1306                 host_client->clientconnectcalled = true;
1307                 prog->globals.server->time = sv.time;
1308                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1309                 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1310
1311                 if ((Sys_DoubleTime() - host_client->connecttime) <= sv.time)
1312                         Con_Printf("%s entered the game\n", host_client->name);
1313
1314                 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1315         }
1316
1317
1318         // send time of update
1319         MSG_WriteByte (&host_client->message, svc_time);
1320         MSG_WriteFloat (&host_client->message, sv.time);
1321
1322         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1323         {
1324                 if (!client->active)
1325                         continue;
1326                 MSG_WriteByte (&host_client->message, svc_updatename);
1327                 MSG_WriteByte (&host_client->message, i);
1328                 MSG_WriteString (&host_client->message, client->name);
1329                 MSG_WriteByte (&host_client->message, svc_updatefrags);
1330                 MSG_WriteByte (&host_client->message, i);
1331                 MSG_WriteShort (&host_client->message, client->frags);
1332                 MSG_WriteByte (&host_client->message, svc_updatecolors);
1333                 MSG_WriteByte (&host_client->message, i);
1334                 MSG_WriteByte (&host_client->message, client->colors);
1335         }
1336
1337         // send all current light styles
1338         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1339         {
1340                 MSG_WriteByte (&host_client->message, svc_lightstyle);
1341                 MSG_WriteByte (&host_client->message, (char)i);
1342                 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1343         }
1344
1345         // send some stats
1346         MSG_WriteByte (&host_client->message, svc_updatestat);
1347         MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1348         MSG_WriteLong (&host_client->message, prog->globals.server->total_secrets);
1349
1350         MSG_WriteByte (&host_client->message, svc_updatestat);
1351         MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1352         MSG_WriteLong (&host_client->message, prog->globals.server->total_monsters);
1353
1354         MSG_WriteByte (&host_client->message, svc_updatestat);
1355         MSG_WriteByte (&host_client->message, STAT_SECRETS);
1356         MSG_WriteLong (&host_client->message, prog->globals.server->found_secrets);
1357
1358         MSG_WriteByte (&host_client->message, svc_updatestat);
1359         MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1360         MSG_WriteLong (&host_client->message, prog->globals.server->killed_monsters);
1361
1362         // send a fixangle
1363         // Never send a roll angle, because savegames can catch the server
1364         // in a state where it is expecting the client to correct the angle
1365         // and it won't happen if the game was just loaded, so you wind up
1366         // with a permanent head tilt
1367         MSG_WriteByte (&host_client->message, svc_setangle);
1368         MSG_WriteAngle (&host_client->message, host_client->edict->fields.server->angles[0], sv.protocol);
1369         MSG_WriteAngle (&host_client->message, host_client->edict->fields.server->angles[1], sv.protocol);
1370         MSG_WriteAngle (&host_client->message, 0, sv.protocol);
1371
1372         SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->message, stats);
1373
1374         MSG_WriteByte (&host_client->message, svc_signonnum);
1375         MSG_WriteByte (&host_client->message, 3);
1376         host_client->sendsignon = true;
1377 }
1378
1379 /*
1380 ==================
1381 Host_Begin_f
1382 ==================
1383 */
1384 void Host_Begin_f (void)
1385 {
1386         if (cmd_source == src_command)
1387         {
1388                 Con_Print("begin is not valid from the console\n");
1389                 return;
1390         }
1391
1392         host_client->spawned = true;
1393 }
1394
1395 //===========================================================================
1396
1397
1398 /*
1399 ==================
1400 Host_Kick_f
1401
1402 Kicks a user off of the server
1403 ==================
1404 */
1405 void Host_Kick_f (void)
1406 {
1407         char *who;
1408         const char *message = NULL;
1409         client_t *save;
1410         int i;
1411         qboolean byNumber = false;
1412
1413         if (cmd_source != src_command || !sv.active)
1414                 return;
1415
1416         SV_VM_Begin();
1417         save = host_client;
1418
1419         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1420         {
1421                 i = atof(Cmd_Argv(2)) - 1;
1422                 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1423                         return;
1424                 byNumber = true;
1425         }
1426         else
1427         {
1428                 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1429                 {
1430                         if (!host_client->active)
1431                                 continue;
1432                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1433                                 break;
1434                 }
1435         }
1436
1437         if (i < svs.maxclients)
1438         {
1439                 if (cmd_source == src_command)
1440                 {
1441                         if (cls.state == ca_dedicated)
1442                                 who = "Console";
1443                         else
1444                                 who = cl_name.string;
1445                 }
1446                 else
1447                         who = save->name;
1448
1449                 // can't kick yourself!
1450                 if (host_client == save)
1451                         return;
1452
1453                 if (Cmd_Argc() > 2)
1454                 {
1455                         message = Cmd_Args();
1456                         COM_ParseToken(&message, false);
1457                         if (byNumber)
1458                         {
1459                                 message++;                                                      // skip the #
1460                                 while (*message == ' ')                         // skip white space
1461                                         message++;
1462                                 message += strlen(Cmd_Argv(2)); // skip the number
1463                         }
1464                         while (*message && *message == ' ')
1465                                 message++;
1466                 }
1467                 if (message)
1468                         SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1469                 else
1470                         SV_ClientPrintf("Kicked by %s\n", who);
1471                 SV_DropClient (false); // kicked
1472         }
1473
1474         host_client = save;
1475         SV_VM_End();
1476 }
1477
1478 /*
1479 ===============================================================================
1480
1481 DEBUGGING TOOLS
1482
1483 ===============================================================================
1484 */
1485
1486 /*
1487 ==================
1488 Host_Give_f
1489 ==================
1490 */
1491 void Host_Give_f (void)
1492 {
1493         const char *t;
1494         int v;
1495         prvm_eval_t *val;
1496
1497         if (cmd_source == src_command)
1498         {
1499                 Cmd_ForwardToServer ();
1500                 return;
1501         }
1502
1503         if (!allowcheats)
1504         {
1505                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1506                 return;
1507         }
1508
1509         t = Cmd_Argv(1);
1510         v = atoi (Cmd_Argv(2));
1511
1512         switch (t[0])
1513         {
1514         case '0':
1515         case '1':
1516         case '2':
1517         case '3':
1518         case '4':
1519         case '5':
1520         case '6':
1521         case '7':
1522         case '8':
1523         case '9':
1524                 // MED 01/04/97 added hipnotic give stuff
1525                 if (gamemode == GAME_HIPNOTIC)
1526                 {
1527                         if (t[0] == '6')
1528                         {
1529                                 if (t[1] == 'a')
1530                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1531                                 else
1532                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1533                         }
1534                         else if (t[0] == '9')
1535                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1536                         else if (t[0] == '0')
1537                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1538                         else if (t[0] >= '2')
1539                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1540                 }
1541                 else
1542                 {
1543                         if (t[0] >= '2')
1544                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1545                 }
1546                 break;
1547
1548         case 's':
1549                 if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1)))
1550                         val->_float = v;
1551
1552                 host_client->edict->fields.server->ammo_shells = v;
1553                 break;
1554         case 'n':
1555                 if (gamemode == GAME_ROGUE)
1556                 {
1557                         if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1)))
1558                         {
1559                                 val->_float = v;
1560                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1561                                         host_client->edict->fields.server->ammo_nails = v;
1562                         }
1563                 }
1564                 else
1565                 {
1566                         host_client->edict->fields.server->ammo_nails = v;
1567                 }
1568                 break;
1569         case 'l':
1570                 if (gamemode == GAME_ROGUE)
1571                 {
1572                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails);
1573                         if (val)
1574                         {
1575                                 val->_float = v;
1576                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1577                                         host_client->edict->fields.server->ammo_nails = v;
1578                         }
1579                 }
1580                 break;
1581         case 'r':
1582                 if (gamemode == GAME_ROGUE)
1583                 {
1584                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1);
1585                         if (val)
1586                         {
1587                                 val->_float = v;
1588                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1589                                         host_client->edict->fields.server->ammo_rockets = v;
1590                         }
1591                 }
1592                 else
1593                 {
1594                         host_client->edict->fields.server->ammo_rockets = v;
1595                 }
1596                 break;
1597         case 'm':
1598                 if (gamemode == GAME_ROGUE)
1599                 {
1600                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets);
1601                         if (val)
1602                         {
1603                                 val->_float = v;
1604                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1605                                         host_client->edict->fields.server->ammo_rockets = v;
1606                         }
1607                 }
1608                 break;
1609         case 'h':
1610                 host_client->edict->fields.server->health = v;
1611                 break;
1612         case 'c':
1613                 if (gamemode == GAME_ROGUE)
1614                 {
1615                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1);
1616                         if (val)
1617                         {
1618                                 val->_float = v;
1619                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1620                                         host_client->edict->fields.server->ammo_cells = v;
1621                         }
1622                 }
1623                 else
1624                 {
1625                         host_client->edict->fields.server->ammo_cells = v;
1626                 }
1627                 break;
1628         case 'p':
1629                 if (gamemode == GAME_ROGUE)
1630                 {
1631                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma);
1632                         if (val)
1633                         {
1634                                 val->_float = v;
1635                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1636                                         host_client->edict->fields.server->ammo_cells = v;
1637                         }
1638                 }
1639                 break;
1640         }
1641 }
1642
1643 prvm_edict_t    *FindViewthing (void)
1644 {
1645         int             i;
1646         prvm_edict_t    *e;
1647
1648         for (i=0 ; i<prog->num_edicts ; i++)
1649         {
1650                 e = PRVM_EDICT_NUM(i);
1651                 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
1652                         return e;
1653         }
1654         Con_Print("No viewthing on map\n");
1655         return NULL;
1656 }
1657
1658 /*
1659 ==================
1660 Host_Viewmodel_f
1661 ==================
1662 */
1663 void Host_Viewmodel_f (void)
1664 {
1665         prvm_edict_t    *e;
1666         model_t *m;
1667
1668         if (!sv.active)
1669                 return;
1670
1671         SV_VM_Begin();
1672         e = FindViewthing ();
1673         SV_VM_End();
1674         if (!e)
1675                 return;
1676
1677         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1678         if (!m)
1679         {
1680                 Con_Printf("Can't load %s\n", Cmd_Argv(1));
1681                 return;
1682         }
1683
1684         e->fields.server->frame = 0;
1685         cl.model_precache[(int)e->fields.server->modelindex] = m;
1686 }
1687
1688 /*
1689 ==================
1690 Host_Viewframe_f
1691 ==================
1692 */
1693 void Host_Viewframe_f (void)
1694 {
1695         prvm_edict_t    *e;
1696         int             f;
1697         model_t *m;
1698
1699         if (!sv.active)
1700                 return;
1701
1702         SV_VM_Begin();
1703         e = FindViewthing ();
1704         SV_VM_End();
1705         if (!e)
1706                 return;
1707         m = cl.model_precache[(int)e->fields.server->modelindex];
1708
1709         f = atoi(Cmd_Argv(1));
1710         if (f >= m->numframes)
1711                 f = m->numframes-1;
1712
1713         e->fields.server->frame = f;
1714 }
1715
1716
1717 void PrintFrameName (model_t *m, int frame)
1718 {
1719         if (m->animscenes)
1720                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1721         else
1722                 Con_Printf("frame %i\n", frame);
1723 }
1724
1725 /*
1726 ==================
1727 Host_Viewnext_f
1728 ==================
1729 */
1730 void Host_Viewnext_f (void)
1731 {
1732         prvm_edict_t    *e;
1733         model_t *m;
1734
1735         if (!sv.active)
1736                 return;
1737
1738         SV_VM_Begin();
1739         e = FindViewthing ();
1740         SV_VM_End();
1741         if (!e)
1742                 return;
1743         m = cl.model_precache[(int)e->fields.server->modelindex];
1744
1745         e->fields.server->frame = e->fields.server->frame + 1;
1746         if (e->fields.server->frame >= m->numframes)
1747                 e->fields.server->frame = m->numframes - 1;
1748
1749         PrintFrameName (m, e->fields.server->frame);
1750 }
1751
1752 /*
1753 ==================
1754 Host_Viewprev_f
1755 ==================
1756 */
1757 void Host_Viewprev_f (void)
1758 {
1759         prvm_edict_t    *e;
1760         model_t *m;
1761
1762         if (!sv.active)
1763                 return;
1764
1765         SV_VM_Begin();
1766         e = FindViewthing ();
1767         SV_VM_End();
1768         if (!e)
1769                 return;
1770
1771         m = cl.model_precache[(int)e->fields.server->modelindex];
1772
1773         e->fields.server->frame = e->fields.server->frame - 1;
1774         if (e->fields.server->frame < 0)
1775                 e->fields.server->frame = 0;
1776
1777         PrintFrameName (m, e->fields.server->frame);
1778 }
1779
1780 /*
1781 ===============================================================================
1782
1783 DEMO LOOP CONTROL
1784
1785 ===============================================================================
1786 */
1787
1788
1789 /*
1790 ==================
1791 Host_Startdemos_f
1792 ==================
1793 */
1794 void Host_Startdemos_f (void)
1795 {
1796         int             i, c;
1797
1798         if (cls.state == ca_dedicated || COM_CheckParm("-listen"))
1799                 return;
1800
1801         c = Cmd_Argc() - 1;
1802         if (c > MAX_DEMOS)
1803         {
1804                 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
1805                 c = MAX_DEMOS;
1806         }
1807         Con_Printf("%i demo(s) in loop\n", c);
1808
1809         for (i=1 ; i<c+1 ; i++)
1810                 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
1811
1812         // LordHavoc: clear the remaining slots
1813         for (;i <= MAX_DEMOS;i++)
1814                 cls.demos[i-1][0] = 0;
1815
1816         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1817         {
1818                 cls.demonum = 0;
1819                 CL_NextDemo ();
1820         }
1821         else
1822                 cls.demonum = -1;
1823 }
1824
1825
1826 /*
1827 ==================
1828 Host_Demos_f
1829
1830 Return to looping demos
1831 ==================
1832 */
1833 void Host_Demos_f (void)
1834 {
1835         if (cls.state == ca_dedicated)
1836                 return;
1837         if (cls.demonum == -1)
1838                 cls.demonum = 1;
1839         CL_Disconnect_f ();
1840         CL_NextDemo ();
1841 }
1842
1843 /*
1844 ==================
1845 Host_Stopdemo_f
1846
1847 Return to looping demos
1848 ==================
1849 */
1850 void Host_Stopdemo_f (void)
1851 {
1852         if (!cls.demoplayback)
1853                 return;
1854         CL_Disconnect ();
1855         Host_ShutdownServer (false);
1856 }
1857
1858 static void MaxPlayers_f(void)
1859 {
1860         int n;
1861
1862         if (Cmd_Argc() != 2)
1863         {
1864                 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
1865                 return;
1866         }
1867
1868         if (sv.active)
1869         {
1870                 Con_Print("maxplayers can not be changed while a server is running.\n");
1871                 return;
1872         }
1873
1874         n = atoi(Cmd_Argv(1));
1875         n = bound(1, n, MAX_SCOREBOARD);
1876         Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1877
1878         if (svs.clients)
1879                 Mem_Free(svs.clients);
1880         svs.maxclients = n;
1881         svs.clients = Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
1882         if (n == 1)
1883                 Cvar_Set ("deathmatch", "0");
1884         else
1885                 Cvar_Set ("deathmatch", "1");
1886 }
1887
1888 //=============================================================================
1889
1890 /*
1891 ==================
1892 Host_InitCommands
1893 ==================
1894 */
1895 void Host_InitCommands (void)
1896 {
1897         Cmd_AddCommand ("status", Host_Status_f);
1898         Cmd_AddCommand ("quit", Host_Quit_f);
1899         if (gamemode == GAME_NEHAHRA)
1900         {
1901                 Cmd_AddCommand ("max", Host_God_f);
1902                 Cmd_AddCommand ("monster", Host_Notarget_f);
1903                 Cmd_AddCommand ("scrag", Host_Fly_f);
1904                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1905                 Cmd_AddCommand ("gimme", Host_Give_f);
1906         }
1907         else
1908         {
1909                 Cmd_AddCommand ("god", Host_God_f);
1910                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1911                 Cmd_AddCommand ("fly", Host_Fly_f);
1912                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1913                 Cmd_AddCommand ("give", Host_Give_f);
1914         }
1915         Cmd_AddCommand ("map", Host_Map_f);
1916         Cmd_AddCommand ("restart", Host_Restart_f);
1917         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1918         Cmd_AddCommand ("connect", Host_Connect_f);
1919         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1920         Cmd_AddCommand ("version", Host_Version_f);
1921         Cmd_AddCommand ("say", Host_Say_f);
1922         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1923         Cmd_AddCommand ("tell", Host_Tell_f);
1924         Cmd_AddCommand ("kill", Host_Kill_f);
1925         Cmd_AddCommand ("pause", Host_Pause_f);
1926         Cmd_AddCommand ("kick", Host_Kick_f);
1927         Cmd_AddCommand ("ping", Host_Ping_f);
1928         Cmd_AddCommand ("load", Host_Loadgame_f);
1929         Cmd_AddCommand ("save", Host_Savegame_f);
1930
1931         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1932         Cmd_AddCommand ("demos", Host_Demos_f);
1933         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1934
1935         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1936         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1937         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1938         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1939
1940         Cvar_RegisterVariable (&cl_name);
1941         Cmd_AddCommand ("name", Host_Name_f);
1942         Cvar_RegisterVariable (&cl_color);
1943         Cmd_AddCommand ("color", Host_Color_f);
1944         Cvar_RegisterVariable (&cl_rate);
1945         Cmd_AddCommand ("rate", Host_Rate_f);
1946         if (gamemode == GAME_NEHAHRA)
1947         {
1948                 Cvar_RegisterVariable (&cl_pmodel);
1949                 Cmd_AddCommand ("pmodel", Host_PModel_f);
1950         }
1951
1952         // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
1953         Cvar_RegisterVariable (&cl_playermodel);
1954         Cmd_AddCommand ("playermodel", Host_Playermodel_f);
1955         Cvar_RegisterVariable (&cl_playerskin);
1956         Cmd_AddCommand ("playerskin", Host_Playerskin_f);
1957
1958         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1959         Cmd_AddCommand ("spawn", Host_Spawn_f);
1960         Cmd_AddCommand ("begin", Host_Begin_f);
1961         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
1962
1963         Cvar_RegisterVariable(&sv_cheats);
1964 }
1965