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