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