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