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