eliminated qbyte type, now uses unsigned char throughout the engine for this purpose
[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         // 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 = (char *)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         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                 if (sv.lightstyles[i][0])
1351                 {
1352                         MSG_WriteByte (&host_client->message, svc_lightstyle);
1353                         MSG_WriteByte (&host_client->message, (char)i);
1354                         MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1355                 }
1356         }
1357
1358         // send some stats
1359         MSG_WriteByte (&host_client->message, svc_updatestat);
1360         MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1361         MSG_WriteLong (&host_client->message, prog->globals.server->total_secrets);
1362
1363         MSG_WriteByte (&host_client->message, svc_updatestat);
1364         MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1365         MSG_WriteLong (&host_client->message, prog->globals.server->total_monsters);
1366
1367         MSG_WriteByte (&host_client->message, svc_updatestat);
1368         MSG_WriteByte (&host_client->message, STAT_SECRETS);
1369         MSG_WriteLong (&host_client->message, prog->globals.server->found_secrets);
1370
1371         MSG_WriteByte (&host_client->message, svc_updatestat);
1372         MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1373         MSG_WriteLong (&host_client->message, prog->globals.server->killed_monsters);
1374
1375         // send a fixangle
1376         // Never send a roll angle, because savegames can catch the server
1377         // in a state where it is expecting the client to correct the angle
1378         // and it won't happen if the game was just loaded, so you wind up
1379         // with a permanent head tilt
1380         MSG_WriteByte (&host_client->message, svc_setangle);
1381         MSG_WriteAngle (&host_client->message, host_client->edict->fields.server->angles[0], sv.protocol);
1382         MSG_WriteAngle (&host_client->message, host_client->edict->fields.server->angles[1], sv.protocol);
1383         MSG_WriteAngle (&host_client->message, 0, sv.protocol);
1384
1385         SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->message, stats);
1386
1387         MSG_WriteByte (&host_client->message, svc_signonnum);
1388         MSG_WriteByte (&host_client->message, 3);
1389         host_client->sendsignon = true;
1390 }
1391
1392 /*
1393 ==================
1394 Host_Begin_f
1395 ==================
1396 */
1397 void Host_Begin_f (void)
1398 {
1399         if (cmd_source == src_command)
1400         {
1401                 Con_Print("begin is not valid from the console\n");
1402                 return;
1403         }
1404
1405         host_client->spawned = true;
1406 }
1407
1408 //===========================================================================
1409
1410
1411 /*
1412 ==================
1413 Host_Kick_f
1414
1415 Kicks a user off of the server
1416 ==================
1417 */
1418 void Host_Kick_f (void)
1419 {
1420         char *who;
1421         const char *message = NULL;
1422         client_t *save;
1423         int i;
1424         qboolean byNumber = false;
1425
1426         if (cmd_source != src_command || !sv.active)
1427                 return;
1428
1429         SV_VM_Begin();
1430         save = host_client;
1431
1432         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1433         {
1434                 i = atof(Cmd_Argv(2)) - 1;
1435                 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1436                         return;
1437                 byNumber = true;
1438         }
1439         else
1440         {
1441                 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1442                 {
1443                         if (!host_client->active)
1444                                 continue;
1445                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1446                                 break;
1447                 }
1448         }
1449
1450         if (i < svs.maxclients)
1451         {
1452                 if (cmd_source == src_command)
1453                 {
1454                         if (cls.state == ca_dedicated)
1455                                 who = "Console";
1456                         else
1457                                 who = cl_name.string;
1458                 }
1459                 else
1460                         who = save->name;
1461
1462                 // can't kick yourself!
1463                 if (host_client == save)
1464                         return;
1465
1466                 if (Cmd_Argc() > 2)
1467                 {
1468                         message = Cmd_Args();
1469                         COM_ParseToken(&message, false);
1470                         if (byNumber)
1471                         {
1472                                 message++;                                                      // skip the #
1473                                 while (*message == ' ')                         // skip white space
1474                                         message++;
1475                                 message += strlen(Cmd_Argv(2)); // skip the number
1476                         }
1477                         while (*message && *message == ' ')
1478                                 message++;
1479                 }
1480                 if (message)
1481                         SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1482                 else
1483                         SV_ClientPrintf("Kicked by %s\n", who);
1484                 SV_DropClient (false); // kicked
1485         }
1486
1487         host_client = save;
1488         SV_VM_End();
1489 }
1490
1491 /*
1492 ===============================================================================
1493
1494 DEBUGGING TOOLS
1495
1496 ===============================================================================
1497 */
1498
1499 /*
1500 ==================
1501 Host_Give_f
1502 ==================
1503 */
1504 void Host_Give_f (void)
1505 {
1506         const char *t;
1507         int v;
1508         prvm_eval_t *val;
1509
1510         if (cmd_source == src_command)
1511         {
1512                 Cmd_ForwardToServer ();
1513                 return;
1514         }
1515
1516         if (!allowcheats)
1517         {
1518                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1519                 return;
1520         }
1521
1522         t = Cmd_Argv(1);
1523         v = atoi (Cmd_Argv(2));
1524
1525         switch (t[0])
1526         {
1527         case '0':
1528         case '1':
1529         case '2':
1530         case '3':
1531         case '4':
1532         case '5':
1533         case '6':
1534         case '7':
1535         case '8':
1536         case '9':
1537                 // MED 01/04/97 added hipnotic give stuff
1538                 if (gamemode == GAME_HIPNOTIC)
1539                 {
1540                         if (t[0] == '6')
1541                         {
1542                                 if (t[1] == 'a')
1543                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1544                                 else
1545                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1546                         }
1547                         else if (t[0] == '9')
1548                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1549                         else if (t[0] == '0')
1550                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1551                         else if (t[0] >= '2')
1552                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1553                 }
1554                 else
1555                 {
1556                         if (t[0] >= '2')
1557                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1558                 }
1559                 break;
1560
1561         case 's':
1562                 if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1)))
1563                         val->_float = v;
1564
1565                 host_client->edict->fields.server->ammo_shells = v;
1566                 break;
1567         case 'n':
1568                 if (gamemode == GAME_ROGUE)
1569                 {
1570                         if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1)))
1571                         {
1572                                 val->_float = v;
1573                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1574                                         host_client->edict->fields.server->ammo_nails = v;
1575                         }
1576                 }
1577                 else
1578                 {
1579                         host_client->edict->fields.server->ammo_nails = v;
1580                 }
1581                 break;
1582         case 'l':
1583                 if (gamemode == GAME_ROGUE)
1584                 {
1585                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails);
1586                         if (val)
1587                         {
1588                                 val->_float = v;
1589                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1590                                         host_client->edict->fields.server->ammo_nails = v;
1591                         }
1592                 }
1593                 break;
1594         case 'r':
1595                 if (gamemode == GAME_ROGUE)
1596                 {
1597                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1);
1598                         if (val)
1599                         {
1600                                 val->_float = v;
1601                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1602                                         host_client->edict->fields.server->ammo_rockets = v;
1603                         }
1604                 }
1605                 else
1606                 {
1607                         host_client->edict->fields.server->ammo_rockets = v;
1608                 }
1609                 break;
1610         case 'm':
1611                 if (gamemode == GAME_ROGUE)
1612                 {
1613                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets);
1614                         if (val)
1615                         {
1616                                 val->_float = v;
1617                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1618                                         host_client->edict->fields.server->ammo_rockets = v;
1619                         }
1620                 }
1621                 break;
1622         case 'h':
1623                 host_client->edict->fields.server->health = v;
1624                 break;
1625         case 'c':
1626                 if (gamemode == GAME_ROGUE)
1627                 {
1628                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1);
1629                         if (val)
1630                         {
1631                                 val->_float = v;
1632                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1633                                         host_client->edict->fields.server->ammo_cells = v;
1634                         }
1635                 }
1636                 else
1637                 {
1638                         host_client->edict->fields.server->ammo_cells = v;
1639                 }
1640                 break;
1641         case 'p':
1642                 if (gamemode == GAME_ROGUE)
1643                 {
1644                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma);
1645                         if (val)
1646                         {
1647                                 val->_float = v;
1648                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1649                                         host_client->edict->fields.server->ammo_cells = v;
1650                         }
1651                 }
1652                 break;
1653         }
1654 }
1655
1656 prvm_edict_t    *FindViewthing (void)
1657 {
1658         int             i;
1659         prvm_edict_t    *e;
1660
1661         for (i=0 ; i<prog->num_edicts ; i++)
1662         {
1663                 e = PRVM_EDICT_NUM(i);
1664                 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
1665                         return e;
1666         }
1667         Con_Print("No viewthing on map\n");
1668         return NULL;
1669 }
1670
1671 /*
1672 ==================
1673 Host_Viewmodel_f
1674 ==================
1675 */
1676 void Host_Viewmodel_f (void)
1677 {
1678         prvm_edict_t    *e;
1679         model_t *m;
1680
1681         if (!sv.active)
1682                 return;
1683
1684         SV_VM_Begin();
1685         e = FindViewthing ();
1686         SV_VM_End();
1687         if (!e)
1688                 return;
1689
1690         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1691         if (!m || !m->loaded || !m->Draw)
1692         {
1693                 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
1694                 return;
1695         }
1696
1697         e->fields.server->frame = 0;
1698         cl.model_precache[(int)e->fields.server->modelindex] = m;
1699 }
1700
1701 /*
1702 ==================
1703 Host_Viewframe_f
1704 ==================
1705 */
1706 void Host_Viewframe_f (void)
1707 {
1708         prvm_edict_t    *e;
1709         int             f;
1710         model_t *m;
1711
1712         if (!sv.active)
1713                 return;
1714
1715         SV_VM_Begin();
1716         e = FindViewthing ();
1717         SV_VM_End();
1718         if (!e)
1719                 return;
1720         m = cl.model_precache[(int)e->fields.server->modelindex];
1721
1722         f = atoi(Cmd_Argv(1));
1723         if (f >= m->numframes)
1724                 f = m->numframes-1;
1725
1726         e->fields.server->frame = f;
1727 }
1728
1729
1730 void PrintFrameName (model_t *m, int frame)
1731 {
1732         if (m->animscenes)
1733                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1734         else
1735                 Con_Printf("frame %i\n", frame);
1736 }
1737
1738 /*
1739 ==================
1740 Host_Viewnext_f
1741 ==================
1742 */
1743 void Host_Viewnext_f (void)
1744 {
1745         prvm_edict_t    *e;
1746         model_t *m;
1747
1748         if (!sv.active)
1749                 return;
1750
1751         SV_VM_Begin();
1752         e = FindViewthing ();
1753         SV_VM_End();
1754         if (!e)
1755                 return;
1756         m = cl.model_precache[(int)e->fields.server->modelindex];
1757
1758         e->fields.server->frame = e->fields.server->frame + 1;
1759         if (e->fields.server->frame >= m->numframes)
1760                 e->fields.server->frame = m->numframes - 1;
1761
1762         PrintFrameName (m, e->fields.server->frame);
1763 }
1764
1765 /*
1766 ==================
1767 Host_Viewprev_f
1768 ==================
1769 */
1770 void Host_Viewprev_f (void)
1771 {
1772         prvm_edict_t    *e;
1773         model_t *m;
1774
1775         if (!sv.active)
1776                 return;
1777
1778         SV_VM_Begin();
1779         e = FindViewthing ();
1780         SV_VM_End();
1781         if (!e)
1782                 return;
1783
1784         m = cl.model_precache[(int)e->fields.server->modelindex];
1785
1786         e->fields.server->frame = e->fields.server->frame - 1;
1787         if (e->fields.server->frame < 0)
1788                 e->fields.server->frame = 0;
1789
1790         PrintFrameName (m, e->fields.server->frame);
1791 }
1792
1793 /*
1794 ===============================================================================
1795
1796 DEMO LOOP CONTROL
1797
1798 ===============================================================================
1799 */
1800
1801
1802 /*
1803 ==================
1804 Host_Startdemos_f
1805 ==================
1806 */
1807 void Host_Startdemos_f (void)
1808 {
1809         int             i, c;
1810
1811         if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-demolooponly"))
1812                 return;
1813
1814         c = Cmd_Argc() - 1;
1815         if (c > MAX_DEMOS)
1816         {
1817                 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
1818                 c = MAX_DEMOS;
1819         }
1820         Con_Printf("%i demo(s) in loop\n", c);
1821
1822         for (i=1 ; i<c+1 ; i++)
1823                 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
1824
1825         // LordHavoc: clear the remaining slots
1826         for (;i <= MAX_DEMOS;i++)
1827                 cls.demos[i-1][0] = 0;
1828
1829         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1830         {
1831                 cls.demonum = 0;
1832                 CL_NextDemo ();
1833         }
1834         else
1835                 cls.demonum = -1;
1836 }
1837
1838
1839 /*
1840 ==================
1841 Host_Demos_f
1842
1843 Return to looping demos
1844 ==================
1845 */
1846 void Host_Demos_f (void)
1847 {
1848         if (cls.state == ca_dedicated)
1849                 return;
1850         if (cls.demonum == -1)
1851                 cls.demonum = 1;
1852         CL_Disconnect_f ();
1853         CL_NextDemo ();
1854 }
1855
1856 /*
1857 ==================
1858 Host_Stopdemo_f
1859
1860 Return to looping demos
1861 ==================
1862 */
1863 void Host_Stopdemo_f (void)
1864 {
1865         if (!cls.demoplayback)
1866                 return;
1867         CL_Disconnect ();
1868         Host_ShutdownServer (false);
1869 }
1870
1871 static void MaxPlayers_f(void)
1872 {
1873         int n;
1874
1875         if (Cmd_Argc() != 2)
1876         {
1877                 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
1878                 return;
1879         }
1880
1881         if (sv.active)
1882         {
1883                 Con_Print("maxplayers can not be changed while a server is running.\n");
1884                 return;
1885         }
1886
1887         n = atoi(Cmd_Argv(1));
1888         n = bound(1, n, MAX_SCOREBOARD);
1889         Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
1890
1891         if (svs.clients)
1892                 Mem_Free(svs.clients);
1893         svs.maxclients = n;
1894         svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
1895         if (n == 1)
1896                 Cvar_Set ("deathmatch", "0");
1897         else
1898                 Cvar_Set ("deathmatch", "1");
1899 }
1900
1901 //=============================================================================
1902
1903 /*
1904 ==================
1905 Host_InitCommands
1906 ==================
1907 */
1908 void Host_InitCommands (void)
1909 {
1910         Cmd_AddCommand ("status", Host_Status_f);
1911         Cmd_AddCommand ("quit", Host_Quit_f);
1912         if (gamemode == GAME_NEHAHRA)
1913         {
1914                 Cmd_AddCommand ("max", Host_God_f);
1915                 Cmd_AddCommand ("monster", Host_Notarget_f);
1916                 Cmd_AddCommand ("scrag", Host_Fly_f);
1917                 Cmd_AddCommand ("wraith", Host_Noclip_f);
1918                 Cmd_AddCommand ("gimme", Host_Give_f);
1919         }
1920         else
1921         {
1922                 Cmd_AddCommand ("god", Host_God_f);
1923                 Cmd_AddCommand ("notarget", Host_Notarget_f);
1924                 Cmd_AddCommand ("fly", Host_Fly_f);
1925                 Cmd_AddCommand ("noclip", Host_Noclip_f);
1926                 Cmd_AddCommand ("give", Host_Give_f);
1927         }
1928         Cmd_AddCommand ("map", Host_Map_f);
1929         Cmd_AddCommand ("restart", Host_Restart_f);
1930         Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1931         Cmd_AddCommand ("connect", Host_Connect_f);
1932         Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1933         Cmd_AddCommand ("version", Host_Version_f);
1934         Cmd_AddCommand ("say", Host_Say_f);
1935         Cmd_AddCommand ("say_team", Host_Say_Team_f);
1936         Cmd_AddCommand ("tell", Host_Tell_f);
1937         Cmd_AddCommand ("kill", Host_Kill_f);
1938         Cmd_AddCommand ("pause", Host_Pause_f);
1939         Cmd_AddCommand ("kick", Host_Kick_f);
1940         Cmd_AddCommand ("ping", Host_Ping_f);
1941         Cmd_AddCommand ("load", Host_Loadgame_f);
1942         Cmd_AddCommand ("save", Host_Savegame_f);
1943
1944         Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1945         Cmd_AddCommand ("demos", Host_Demos_f);
1946         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1947
1948         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1949         Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1950         Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1951         Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1952
1953         Cvar_RegisterVariable (&cl_name);
1954         Cmd_AddCommand ("name", Host_Name_f);
1955         Cvar_RegisterVariable (&cl_color);
1956         Cmd_AddCommand ("color", Host_Color_f);
1957         Cvar_RegisterVariable (&cl_rate);
1958         Cmd_AddCommand ("rate", Host_Rate_f);
1959         if (gamemode == GAME_NEHAHRA)
1960         {
1961                 Cvar_RegisterVariable (&cl_pmodel);
1962                 Cmd_AddCommand ("pmodel", Host_PModel_f);
1963         }
1964
1965         // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
1966         Cvar_RegisterVariable (&cl_playermodel);
1967         Cmd_AddCommand ("playermodel", Host_Playermodel_f);
1968         Cvar_RegisterVariable (&cl_playerskin);
1969         Cmd_AddCommand ("playerskin", Host_Playerskin_f);
1970
1971         Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1972         Cmd_AddCommand ("spawn", Host_Spawn_f);
1973         Cmd_AddCommand ("begin", Host_Begin_f);
1974         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
1975
1976         Cvar_RegisterVariable(&sv_cheats);
1977 }
1978