]> icculus.org git repositories - divverent/darkplaces.git/blob - host_cmd.c
don't allow $ expansion or sendcvar on rcon_password (added CVAR_PRIVATE flag for...
[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 #include "libcurl.h"
23
24 int current_skill;
25 cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
26 cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands"};
27 cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
28 cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
29 cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
30 cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
31 qboolean allowcheats = false;
32
33 /*
34 ==================
35 Host_Quit_f
36 ==================
37 */
38
39 void Host_Quit_f (void)
40 {
41         Sys_Quit ();
42 }
43
44
45 /*
46 ==================
47 Host_Status_f
48 ==================
49 */
50 void Host_Status_f (void)
51 {
52         client_t *client;
53         int seconds, minutes, hours = 0, j, players;
54         void (*print) (const char *fmt, ...);
55
56         if (cmd_source == src_command)
57         {
58                 if (!sv.active)
59                 {
60                         Cmd_ForwardToServer ();
61                         return;
62                 }
63                 print = Con_Printf;
64         }
65         else
66                 print = SV_ClientPrintf;
67
68         for (players = 0, j = 0;j < svs.maxclients;j++)
69                 if (svs.clients[j].active)
70                         players++;
71         print ("host:     %s\n", Cvar_VariableString ("hostname"));
72         print ("version:  %s build %s\n", gamename, buildstring);
73         print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
74         print ("map:      %s\n", sv.name);
75         print ("players:  %i active (%i max)\n\n", players, svs.maxclients);
76         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
77         {
78                 if (!client->active)
79                         continue;
80                 seconds = (int)(realtime - client->connecttime);
81                 minutes = seconds / 60;
82                 if (minutes)
83                 {
84                         seconds -= (minutes * 60);
85                         hours = minutes / 60;
86                         if (hours)
87                                 minutes -= (hours * 60);
88                 }
89                 else
90                         hours = 0;
91                 print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->fields.server->frags, hours, minutes, seconds);
92                 print ("   %s\n", client->netconnection ? client->netconnection->address : "botclient");
93         }
94 }
95
96
97 /*
98 ==================
99 Host_God_f
100
101 Sets client to godmode
102 ==================
103 */
104 void Host_God_f (void)
105 {
106         if (cmd_source == src_command)
107         {
108                 Cmd_ForwardToServer ();
109                 return;
110         }
111
112         if (!allowcheats)
113         {
114                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
115                 return;
116         }
117
118         host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
119         if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
120                 SV_ClientPrint("godmode OFF\n");
121         else
122                 SV_ClientPrint("godmode ON\n");
123 }
124
125 void Host_Notarget_f (void)
126 {
127         if (cmd_source == src_command)
128         {
129                 Cmd_ForwardToServer ();
130                 return;
131         }
132
133         if (!allowcheats)
134         {
135                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
136                 return;
137         }
138
139         host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
140         if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
141                 SV_ClientPrint("notarget OFF\n");
142         else
143                 SV_ClientPrint("notarget ON\n");
144 }
145
146 qboolean noclip_anglehack;
147
148 void Host_Noclip_f (void)
149 {
150         if (cmd_source == src_command)
151         {
152                 Cmd_ForwardToServer ();
153                 return;
154         }
155
156         if (!allowcheats)
157         {
158                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
159                 return;
160         }
161
162         if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
163         {
164                 noclip_anglehack = true;
165                 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
166                 SV_ClientPrint("noclip ON\n");
167         }
168         else
169         {
170                 noclip_anglehack = false;
171                 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
172                 SV_ClientPrint("noclip OFF\n");
173         }
174 }
175
176 /*
177 ==================
178 Host_Fly_f
179
180 Sets client to flymode
181 ==================
182 */
183 void Host_Fly_f (void)
184 {
185         if (cmd_source == src_command)
186         {
187                 Cmd_ForwardToServer ();
188                 return;
189         }
190
191         if (!allowcheats)
192         {
193                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
194                 return;
195         }
196
197         if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
198         {
199                 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
200                 SV_ClientPrint("flymode ON\n");
201         }
202         else
203         {
204                 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
205                 SV_ClientPrint("flymode OFF\n");
206         }
207 }
208
209
210 /*
211 ==================
212 Host_Ping_f
213
214 ==================
215 */
216 void Host_Ping_f (void)
217 {
218         int i;
219         client_t *client;
220         void (*print) (const char *fmt, ...);
221
222         if (cmd_source == src_command)
223         {
224                 if (!sv.active)
225                 {
226                         Cmd_ForwardToServer ();
227                         return;
228                 }
229                 print = Con_Printf;
230         }
231         else
232                 print = SV_ClientPrintf;
233
234         print("Client ping times:\n");
235         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
236         {
237                 if (!client->active)
238                         continue;
239                 print("%4i %s\n", (int)floor(client->ping*1000+0.5), client->name);
240         }
241 }
242
243 /*
244 ===============================================================================
245
246 SERVER TRANSITIONS
247
248 ===============================================================================
249 */
250
251 /*
252 ======================
253 Host_Map_f
254
255 handle a
256 map <servername>
257 command from the console.  Active clients are kicked off.
258 ======================
259 */
260 void Host_Map_f (void)
261 {
262         char level[MAX_QPATH];
263
264         if (Cmd_Argc() != 2)
265         {
266                 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
267                 return;
268         }
269
270         if (cmd_source != src_command)
271                 return;
272
273         cls.demonum = -1;               // stop demo loop in case this fails
274
275         CL_Disconnect ();
276         Host_ShutdownServer();
277
278         // remove menu
279         key_dest = key_game;
280
281         svs.serverflags = 0;                    // haven't completed an episode yet
282         allowcheats = sv_cheats.integer != 0;
283         strcpy(level, Cmd_Argv(1));
284         SV_SpawnServer(level);
285         if (sv.active && cls.state == ca_disconnected)
286                 CL_EstablishConnection("local:1");
287
288 #ifdef AUTODEMO_BROKEN
289 // if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
290         if (cl_autodemo.integer && !cls.demorecording)
291         {
292                 char demofile[MAX_OSPATH];
293
294                 dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), level);
295
296                 Con_Printf ("Recording to %s.\n", demofile);
297
298                 cls.demofile = FS_Open (demofile, "wb", false, false);
299                 if (cls.demofile)
300                 {
301                         cls.forcetrack = -1;
302                         FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
303                 }
304                 else
305                         Con_Print ("ERROR: couldn't open.\n");
306
307                 cls.demorecording = true;
308         }
309 #endif
310 }
311
312 /*
313 ==================
314 Host_Changelevel_f
315
316 Goes to a new map, taking all clients along
317 ==================
318 */
319 void Host_Changelevel_f (void)
320 {
321         char level[MAX_QPATH];
322
323         if (Cmd_Argc() != 2)
324         {
325                 Con_Print("changelevel <levelname> : continue game on a new level\n");
326                 return;
327         }
328         // HACKHACKHACK
329         if (!sv.active) {
330                 Host_Map_f();
331                 return;
332         }
333         if (cmd_source != src_command)
334                 return;
335
336         // remove menu
337         key_dest = key_game;
338
339         SV_VM_Begin();
340         SV_SaveSpawnparms ();
341         SV_VM_End();
342         allowcheats = sv_cheats.integer != 0;
343         strcpy(level, Cmd_Argv(1));
344         SV_SpawnServer(level);
345         if (sv.active && cls.state == ca_disconnected)
346                 CL_EstablishConnection("local:1");
347 }
348
349 /*
350 ==================
351 Host_Restart_f
352
353 Restarts the current server for a dead player
354 ==================
355 */
356 void Host_Restart_f (void)
357 {
358         char mapname[MAX_QPATH];
359
360         if (Cmd_Argc() != 1)
361         {
362                 Con_Print("restart : restart current level\n");
363                 return;
364         }
365         if (!sv.active)
366         {
367                 Con_Print("Only the server may restart\n");
368                 return;
369         }
370         if (cmd_source != src_command)
371                 return;
372
373         // remove menu
374         key_dest = key_game;
375
376         allowcheats = sv_cheats.integer != 0;
377         strcpy(mapname, sv.name);
378         SV_SpawnServer(mapname);
379         if (sv.active && cls.state == ca_disconnected)
380                 CL_EstablishConnection("local:1");
381 }
382
383 /*
384 ==================
385 Host_Reconnect_f
386
387 This command causes the client to wait for the signon messages again.
388 This is sent just before a server changes levels
389 ==================
390 */
391 void Host_Reconnect_f (void)
392 {
393         if (cls.protocol == PROTOCOL_QUAKEWORLD)
394         {
395                 if (cls.qw_downloadmemory)  // don't change when downloading
396                         return;
397
398                 S_StopAllSounds();
399
400                 if (cls.netcon)
401                 {
402                         if (cls.state == ca_connected && cls.signon < SIGNONS)
403                         {
404                                 Con_Printf("reconnecting...\n");
405                                 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
406                                 MSG_WriteString(&cls.netcon->message, "new");
407                         }
408                         else
409                         {
410                                 char temp[128];
411                                 // if we have connected to a server recently, the userinfo
412                                 // will still contain its IP address, so get the address...
413                                 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
414                                 if (temp[0])
415                                         CL_EstablishConnection(temp);
416                                 else
417                                         Con_Printf("Reconnect to what server?  (you have not connected to a server yet)\n");
418                         }
419                 }
420         }
421         else
422         {
423                 if (Cmd_Argc() != 1)
424                 {
425                         Con_Print("reconnect : wait for signon messages again\n");
426                         return;
427                 }
428                 if (!cls.signon)
429                 {
430                         Con_Print("reconnect: no signon, ignoring reconnect\n");
431                         return;
432                 }
433                 cls.signon = 0;         // need new connection messages
434         }
435 }
436
437 /*
438 =====================
439 Host_Connect_f
440
441 User command to connect to server
442 =====================
443 */
444 void Host_Connect_f (void)
445 {
446         if (Cmd_Argc() != 2)
447         {
448                 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
449                 return;
450         }
451         CL_EstablishConnection(Cmd_Argv(1));
452 }
453
454
455 /*
456 ===============================================================================
457
458 LOAD / SAVE GAME
459
460 ===============================================================================
461 */
462
463 #define SAVEGAME_VERSION        5
464
465 /*
466 ===============
467 Host_SavegameComment
468
469 Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
470 ===============
471 */
472 void Host_SavegameComment (char *text)
473 {
474         int             i;
475         char    kills[20];
476
477         for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
478                 text[i] = ' ';
479         // LordHavoc: added min() to prevent overflow
480         memcpy (text, cl.levelname, min(strlen(cl.levelname), SAVEGAME_COMMENT_LENGTH));
481         sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
482         memcpy (text+22, kills, strlen(kills));
483         // convert space to _ to make stdio happy
484         // LordHavoc: convert control characters to _ as well
485         for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
486                 if (text[i] <= ' ')
487                         text[i] = '_';
488         text[SAVEGAME_COMMENT_LENGTH] = '\0';
489 }
490
491
492 /*
493 ===============
494 Host_Savegame_f
495 ===============
496 */
497 void Host_Savegame_f (void)
498 {
499         char    name[MAX_QPATH];
500         qfile_t *f;
501         int             i;
502         char    comment[SAVEGAME_COMMENT_LENGTH+1];
503
504         if (cmd_source != src_command)
505                 return;
506
507         if (cls.state != ca_connected || !sv.active)
508         {
509                 Con_Print("Not playing a local game.\n");
510                 return;
511         }
512
513         if (cl.intermission)
514         {
515                 Con_Print("Can't save in intermission.\n");
516                 return;
517         }
518
519         for (i = 0;i < svs.maxclients;i++)
520         {
521                 if (svs.clients[i].active)
522                 {
523                         if (i > 0)
524                         {
525                                 Con_Print("Can't save multiplayer games.\n");
526                                 return;
527                         }
528                         if (svs.clients[i].edict->fields.server->deadflag)
529                         {
530                                 Con_Print("Can't savegame with a dead player\n");
531                                 return;
532                         }
533                 }
534         }
535
536         if (Cmd_Argc() != 2)
537         {
538                 Con_Print("save <savename> : save a game\n");
539                 return;
540         }
541
542         if (strstr(Cmd_Argv(1), ".."))
543         {
544                 Con_Print("Relative pathnames are not allowed.\n");
545                 return;
546         }
547
548         strlcpy (name, Cmd_Argv(1), sizeof (name));
549         FS_DefaultExtension (name, ".sav", sizeof (name));
550
551         Con_Printf("Saving game to %s...\n", name);
552         f = FS_Open (name, "wb", false, false);
553         if (!f)
554         {
555                 Con_Print("ERROR: couldn't open.\n");
556                 return;
557         }
558
559         FS_Printf(f, "%i\n", SAVEGAME_VERSION);
560         Host_SavegameComment (comment);
561         FS_Printf(f, "%s\n", comment);
562         for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
563                 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
564         FS_Printf(f, "%d\n", current_skill);
565         FS_Printf(f, "%s\n", sv.name);
566         FS_Printf(f, "%f\n",sv.time);
567
568         // write the light styles
569         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
570         {
571                 if (sv.lightstyles[i][0])
572                         FS_Printf(f, "%s\n", sv.lightstyles[i]);
573                 else
574                         FS_Print(f,"m\n");
575         }
576
577         SV_VM_Begin();
578
579         PRVM_ED_WriteGlobals (f);
580         for (i=0 ; i<prog->num_edicts ; i++)
581                 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
582
583         SV_VM_End();
584
585         FS_Close (f);
586         Con_Print("done.\n");
587 }
588
589
590 /*
591 ===============
592 Host_Loadgame_f
593 ===============
594 */
595 void Host_Loadgame_f (void)
596 {
597         char filename[MAX_QPATH];
598         char mapname[MAX_QPATH];
599         float time;
600         const char *start;
601         const char *t;
602         const char *oldt;
603         char *text;
604         prvm_edict_t *ent;
605         int i;
606         int entnum;
607         int version;
608         float spawn_parms[NUM_SPAWN_PARMS];
609
610         if (cmd_source != src_command)
611                 return;
612
613         if (Cmd_Argc() != 2)
614         {
615                 Con_Print("load <savename> : load a game\n");
616                 return;
617         }
618
619         strcpy (filename, Cmd_Argv(1));
620         FS_DefaultExtension (filename, ".sav", sizeof (filename));
621
622         Con_Printf("Loading game from %s...\n", filename);
623
624         cls.demonum = -1;               // stop demo loop in case this fails
625
626         t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
627         if (!text)
628         {
629                 Con_Print("ERROR: couldn't open.\n");
630                 return;
631         }
632
633         // version
634         COM_ParseToken(&t, false);
635         version = atoi(com_token);
636         if (version != SAVEGAME_VERSION)
637         {
638                 Mem_Free(text);
639                 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
640                 return;
641         }
642
643         // description
644         // this is a little hard to parse, as : is a separator in COM_ParseToken,
645         // so use the console parser instead
646         COM_ParseTokenConsole(&t);
647
648         for (i = 0;i < NUM_SPAWN_PARMS;i++)
649         {
650                 COM_ParseToken(&t, false);
651                 spawn_parms[i] = atof(com_token);
652         }
653         // skill
654         COM_ParseToken(&t, false);
655 // this silliness is so we can load 1.06 save files, which have float skill values
656         current_skill = (int)(atof(com_token) + 0.5);
657         Cvar_SetValue ("skill", (float)current_skill);
658
659         // mapname
660         COM_ParseToken(&t, false);
661         strcpy (mapname, com_token);
662
663         // time
664         COM_ParseToken(&t, false);
665         time = atof(com_token);
666
667         allowcheats = sv_cheats.integer != 0;
668
669         SV_SpawnServer (mapname);
670         if (!sv.active)
671         {
672                 Mem_Free(text);
673                 Con_Print("Couldn't load map\n");
674                 return;
675         }
676         sv.paused = true;               // pause until all clients connect
677         sv.loadgame = true;
678
679 // load the light styles
680
681         for (i = 0;i < MAX_LIGHTSTYLES;i++)
682         {
683                 // light style
684                 oldt = t;
685                 COM_ParseToken(&t, false);
686                 // if this is a 64 lightstyle savegame produced by Quake, stop now
687                 // we have to check this because darkplaces saves 256 lightstyle savegames
688                 if (com_token[0] == '{')
689                 {
690                         t = oldt;
691                         break;
692                 }
693                 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
694         }
695
696         // now skip everything before the first opening brace
697         // (this is for forward compatibility, so that older versions (at
698         // least ones with this fix) can load savegames with extra data before the
699         // first brace, as might be produced by a later engine version)
700         for(;;)
701         {
702                 oldt = t;
703                 COM_ParseToken(&t, false);
704                 if (com_token[0] == '{')
705                 {
706                         t = oldt;
707                         break;
708                 }
709         }
710
711 // load the edicts out of the savegame file
712         SV_VM_Begin();
713         // -1 is the globals
714         entnum = -1;
715         for (;;)
716         {
717                 start = t;
718                 while (COM_ParseToken(&t, false))
719                         if (!strcmp(com_token, "}"))
720                                 break;
721                 if (!COM_ParseToken(&start, false))
722                 {
723                         // end of file
724                         break;
725                 }
726                 if (strcmp(com_token,"{"))
727                 {
728                         Mem_Free(text);
729                         Host_Error ("First token isn't a brace");
730                 }
731
732                 if (entnum == -1)
733                 {
734                         // parse the global vars
735                         PRVM_ED_ParseGlobals (start);
736                 }
737                 else
738                 {
739                         // parse an edict
740                         if (entnum >= MAX_EDICTS)
741                         {
742                                 Mem_Free(text);
743                                 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
744                         }
745                         while (entnum >= prog->max_edicts)
746                                 //SV_IncreaseEdicts();
747                                 PRVM_MEM_IncreaseEdicts();
748                         ent = PRVM_EDICT_NUM(entnum);
749                         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
750                         ent->priv.server->free = false;
751                         PRVM_ED_ParseEdict (start, ent);
752
753                         // link it into the bsp tree
754                         if (!ent->priv.server->free)
755                                 SV_LinkEdict (ent, false);
756                 }
757
758                 entnum++;
759         }
760         Mem_Free(text);
761
762         prog->num_edicts = entnum;
763         sv.time = time;
764
765         for (i = 0;i < NUM_SPAWN_PARMS;i++)
766                 svs.clients[0].spawn_parms[i] = spawn_parms[i];
767
768         SV_VM_End();
769
770         // make sure we're connected to loopback
771         if (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP))
772                 CL_EstablishConnection("local:1");
773 }
774
775 //============================================================================
776
777 /*
778 ======================
779 Host_Name_f
780 ======================
781 */
782 cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
783 void Host_Name_f (void)
784 {
785         int i, j;
786         char newName[sizeof(host_client->name)];
787
788         if (Cmd_Argc () == 1)
789         {
790                 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
791                 return;
792         }
793
794         if (Cmd_Argc () == 2)
795                 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
796         else
797                 strlcpy (newName, Cmd_Args(), sizeof (newName));
798
799         for (i = 0, j = 0;newName[i];i++)
800                 if (newName[i] != '\r' && newName[i] != '\n')
801                         newName[j++] = newName[i];
802         newName[j] = 0;
803
804         if (cmd_source == src_command)
805         {
806                 Cvar_Set ("_cl_name", newName);
807                 CL_SetInfo("name", newName, true, false, false, false);
808                 return;
809         }
810
811         if (sv.time < host_client->nametime)
812         {
813                 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
814                 return;
815         }
816
817         host_client->nametime = sv.time + 5;
818
819         // point the string back at updateclient->name to keep it safe
820         strlcpy (host_client->name, newName, sizeof (host_client->name));
821         host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
822         if (strcmp(host_client->old_name, host_client->name))
823         {
824                 if (host_client->spawned)
825                         SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
826                 strcpy(host_client->old_name, host_client->name);
827                 // send notification to all clients
828                 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
829                 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
830                 MSG_WriteString (&sv.reliable_datagram, host_client->name);
831         }
832 }
833
834 /*
835 ======================
836 Host_Playermodel_f
837 ======================
838 */
839 cvar_t cl_playermodel = {CVAR_SAVE, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
840 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
841 void Host_Playermodel_f (void)
842 {
843         int i, j;
844         char newPath[sizeof(host_client->playermodel)];
845
846         if (Cmd_Argc () == 1)
847         {
848                 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
849                 return;
850         }
851
852         if (Cmd_Argc () == 2)
853                 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
854         else
855                 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
856
857         for (i = 0, j = 0;newPath[i];i++)
858                 if (newPath[i] != '\r' && newPath[i] != '\n')
859                         newPath[j++] = newPath[i];
860         newPath[j] = 0;
861
862         if (cmd_source == src_command)
863         {
864                 Cvar_Set ("_cl_playermodel", newPath);
865                 CL_SetInfo("playermodel", newPath, true, false, false, false);
866                 return;
867         }
868
869         /*
870         if (sv.time < host_client->nametime)
871         {
872                 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
873                 return;
874         }
875
876         host_client->nametime = sv.time + 5;
877         */
878
879         // point the string back at updateclient->name to keep it safe
880         strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
881         if( eval_playermodel )
882                 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
883         if (strcmp(host_client->old_model, host_client->playermodel))
884         {
885                 strcpy(host_client->old_model, host_client->playermodel);
886                 /*// send notification to all clients
887                 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
888                 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
889                 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
890         }
891 }
892
893 /*
894 ======================
895 Host_Playerskin_f
896 ======================
897 */
898 cvar_t cl_playerskin = {CVAR_SAVE, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
899 void Host_Playerskin_f (void)
900 {
901         int i, j;
902         char newPath[sizeof(host_client->playerskin)];
903
904         if (Cmd_Argc () == 1)
905         {
906                 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
907                 return;
908         }
909
910         if (Cmd_Argc () == 2)
911                 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
912         else
913                 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
914
915         for (i = 0, j = 0;newPath[i];i++)
916                 if (newPath[i] != '\r' && newPath[i] != '\n')
917                         newPath[j++] = newPath[i];
918         newPath[j] = 0;
919
920         if (cmd_source == src_command)
921         {
922                 Cvar_Set ("_cl_playerskin", newPath);
923                 CL_SetInfo("playerskin", newPath, true, false, false, false);
924                 return;
925         }
926
927         /*
928         if (sv.time < host_client->nametime)
929         {
930                 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
931                 return;
932         }
933
934         host_client->nametime = sv.time + 5;
935         */
936
937         // point the string back at updateclient->name to keep it safe
938         strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
939         if( eval_playerskin )
940                 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
941         if (strcmp(host_client->old_skin, host_client->playerskin))
942         {
943                 //if (host_client->spawned)
944                 //      SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
945                 strcpy(host_client->old_skin, host_client->playerskin);
946                 /*// send notification to all clients
947                 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
948                 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
949                 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
950         }
951 }
952
953 void Host_Version_f (void)
954 {
955         Con_Printf("Version: %s build %s\n", gamename, buildstring);
956 }
957
958 void Host_Say(qboolean teamonly)
959 {
960         client_t *save;
961         int j, quoted;
962         const char *p1;
963         char *p2;
964         // LordHavoc: long say messages
965         char text[1024];
966         qboolean fromServer = false;
967
968         if (cmd_source == src_command)
969         {
970                 if (cls.state == ca_dedicated)
971                 {
972                         fromServer = true;
973                         teamonly = false;
974                 }
975                 else
976                 {
977                         Cmd_ForwardToServer ();
978                         return;
979                 }
980         }
981
982         if (Cmd_Argc () < 2)
983                 return;
984
985         if (!teamplay.integer)
986                 teamonly = false;
987
988         p1 = Cmd_Args();
989         quoted = false;
990         if (*p1 == '\"')
991         {
992                 quoted = true;
993                 p1++;
994         }
995         // note this uses the chat prefix \001
996         if (!fromServer)
997                 dpsnprintf (text, sizeof(text), "\001%s" STRING_COLOR_DEFAULT_STR ": %s", host_client->name, p1);
998         else
999                 dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", hostname.string, p1);
1000         p2 = text + strlen(text);
1001         while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1002         {
1003                 if (p2[-1] == '\"' && quoted)
1004                         quoted = false;
1005                 p2[-1] = 0;
1006                 p2--;
1007         }
1008         strlcat(text, "\n", sizeof(text));
1009
1010         // note: save is not a valid edict if fromServer is true
1011         save = host_client;
1012         for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1013                 if (host_client->spawned && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1014                         SV_ClientPrint(text);
1015         host_client = save;
1016
1017         if (cls.state == ca_dedicated)
1018                 Con_Print(&text[1]);
1019 }
1020
1021
1022 void Host_Say_f(void)
1023 {
1024         Host_Say(false);
1025 }
1026
1027
1028 void Host_Say_Team_f(void)
1029 {
1030         Host_Say(true);
1031 }
1032
1033
1034 void Host_Tell_f(void)
1035 {
1036         client_t *save;
1037         int j;
1038         const char *p1, *p2;
1039         char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1040         qboolean fromServer = false;
1041
1042         if (cmd_source == src_command)
1043         {
1044                 if (cls.state == ca_dedicated)
1045                         fromServer = true;
1046                 else
1047                 {
1048                         Cmd_ForwardToServer ();
1049                         return;
1050                 }
1051         }
1052
1053         if (Cmd_Argc () < 3)
1054                 return;
1055
1056         // note this uses the chat prefix \001
1057         if (!fromServer)
1058                 sprintf (text, "\001%s tells you: ", host_client->name);
1059         else
1060                 sprintf (text, "\001<%s tells you> ", hostname.string);
1061
1062         p1 = Cmd_Args();
1063         p2 = p1 + strlen(p1);
1064         // remove the target name
1065         while (p1 < p2 && *p1 != ' ')
1066                 p1++;
1067         while (p1 < p2 && *p1 == ' ')
1068                 p1++;
1069         // remove trailing newlines
1070         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1071                 p2--;
1072         // remove quotes if present
1073         if (*p1 == '"')
1074         {
1075                 p1++;
1076                 if (p2[-1] == '"')
1077                         p2--;
1078                 else if (fromServer)
1079                         Con_Print("Host_Tell: missing end quote\n");
1080                 else
1081                         SV_ClientPrint("Host_Tell: missing end quote\n");
1082         }
1083         while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1084                 p2--;
1085         for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1086                 text[j++] = *p1++;
1087         text[j++] = '\n';
1088         text[j++] = 0;
1089
1090         save = host_client;
1091         for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1092                 if (host_client->spawned && !strcasecmp(host_client->name, Cmd_Argv(1)))
1093                         SV_ClientPrint(text);
1094         host_client = save;
1095 }
1096
1097
1098 /*
1099 ==================
1100 Host_Color_f
1101 ==================
1102 */
1103 cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1104 void Host_Color(int changetop, int changebottom)
1105 {
1106         int top, bottom, playercolor;
1107         mfunction_t *f;
1108         func_t SV_ChangeTeam;
1109
1110         // get top and bottom either from the provided values or the current values
1111         // (allows changing only top or bottom, or both at once)
1112         top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1113         bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1114
1115         top &= 15;
1116         bottom &= 15;
1117         // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1118         //if (top > 13)
1119         //      top = 13;
1120         //if (bottom > 13)
1121         //      bottom = 13;
1122
1123         playercolor = top*16 + bottom;
1124
1125         if (cmd_source == src_command)
1126         {
1127                 Cvar_SetValueQuick(&cl_color, playercolor);
1128                 if (changetop >= 0)
1129                         CL_SetInfo("topcolor", va("%i", top), true, false, false, false);
1130                 if (changebottom >= 0)
1131                         CL_SetInfo("bottomcolor", va("%i", bottom), true, false, false, false);
1132                 if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon)
1133                 {
1134                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1135                         MSG_WriteString(&cls.netcon->message, va("color %i %i", top, bottom));
1136                 }
1137                 return;
1138         }
1139
1140         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1141                 return;
1142
1143         if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions)))
1144         {
1145                 Con_DPrint("Calling SV_ChangeTeam\n");
1146                 prog->globals.server->time = sv.time;
1147                 prog->globals.generic[OFS_PARM0] = playercolor;
1148                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1149                 PRVM_ExecuteProgram (SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1150         }
1151         else
1152         {
1153                 prvm_eval_t *val;
1154                 if (host_client->edict)
1155                 {
1156                         if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1157                                 val->_float = playercolor;
1158                         host_client->edict->fields.server->team = bottom + 1;
1159                 }
1160                 host_client->colors = playercolor;
1161                 if (host_client->old_colors != host_client->colors)
1162                 {
1163                         host_client->old_colors = host_client->colors;
1164                         // send notification to all clients
1165                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1166                         MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1167                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1168                 }
1169         }
1170 }
1171
1172 void Host_Color_f(void)
1173 {
1174         int             top, bottom;
1175
1176         if (Cmd_Argc() == 1)
1177         {
1178                 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1179                 Con_Print("color <0-15> [0-15]\n");
1180                 return;
1181         }
1182
1183         if (Cmd_Argc() == 2)
1184                 top = bottom = atoi(Cmd_Argv(1));
1185         else
1186         {
1187                 top = atoi(Cmd_Argv(1));
1188                 bottom = atoi(Cmd_Argv(2));
1189         }
1190         Host_Color(top, bottom);
1191 }
1192
1193 void Host_TopColor_f(void)
1194 {
1195         if (Cmd_Argc() == 1)
1196         {
1197                 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1198                 Con_Print("topcolor <0-15>\n");
1199                 return;
1200         }
1201
1202         Host_Color(atoi(Cmd_Argv(1)), -1);
1203 }
1204
1205 void Host_BottomColor_f(void)
1206 {
1207         if (Cmd_Argc() == 1)
1208         {
1209                 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1210                 Con_Print("bottomcolor <0-15>\n");
1211                 return;
1212         }
1213
1214         Host_Color(-1, atoi(Cmd_Argv(1)));
1215 }
1216
1217 cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000", "internal storage cvar for current rate (changed by rate command)"};
1218 void Host_Rate_f(void)
1219 {
1220         int rate;
1221
1222         if (Cmd_Argc() != 2)
1223         {
1224                 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1225                 Con_Print("rate <500-25000>\n");
1226                 return;
1227         }
1228
1229         rate = atoi(Cmd_Argv(1));
1230
1231         if (cmd_source == src_command)
1232         {
1233                 Cvar_SetValue ("_cl_rate", bound(NET_MINRATE, rate, NET_MAXRATE));
1234                 CL_SetInfo("rate", va("%i", rate), true, false, false, false);
1235                 return;
1236         }
1237
1238         host_client->rate = rate;
1239 }
1240
1241 /*
1242 ==================
1243 Host_Kill_f
1244 ==================
1245 */
1246 void Host_Kill_f (void)
1247 {
1248         if (cmd_source == src_command)
1249         {
1250                 Cmd_ForwardToServer ();
1251                 return;
1252         }
1253
1254         if (host_client->edict->fields.server->health <= 0)
1255         {
1256                 SV_ClientPrint("Can't suicide -- already dead!\n");
1257                 return;
1258         }
1259
1260         prog->globals.server->time = sv.time;
1261         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1262         PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1263 }
1264
1265
1266 /*
1267 ==================
1268 Host_Pause_f
1269 ==================
1270 */
1271 void Host_Pause_f (void)
1272 {
1273
1274         if (cmd_source == src_command)
1275         {
1276                 Cmd_ForwardToServer ();
1277                 return;
1278         }
1279         if (!pausable.integer)
1280                 SV_ClientPrint("Pause not allowed.\n");
1281         else
1282         {
1283                 sv.paused ^= 1;
1284                 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1285                 // send notification to all clients
1286                 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1287                 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1288         }
1289 }
1290
1291 /*
1292 ======================
1293 Host_PModel_f
1294 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1295 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1296 ======================
1297 */
1298 cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
1299 static void Host_PModel_f (void)
1300 {
1301         int i;
1302         prvm_eval_t *val;
1303
1304         if (Cmd_Argc () == 1)
1305         {
1306                 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1307                 return;
1308         }
1309         i = atoi(Cmd_Argv(1));
1310
1311         if (cmd_source == src_command)
1312         {
1313                 if (cl_pmodel.integer == i)
1314                         return;
1315                 Cvar_SetValue ("_cl_pmodel", i);
1316                 if (cls.state == ca_connected)
1317                         Cmd_ForwardToServer ();
1318                 return;
1319         }
1320
1321         if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
1322                 val->_float = i;
1323 }
1324
1325 //===========================================================================
1326
1327
1328 /*
1329 ==================
1330 Host_PreSpawn_f
1331 ==================
1332 */
1333 void Host_PreSpawn_f (void)
1334 {
1335         if (cmd_source == src_command)
1336         {
1337                 Con_Print("prespawn is not valid from the console\n");
1338                 return;
1339         }
1340
1341         if (host_client->spawned)
1342         {
1343                 Con_Print("prespawn not valid -- already spawned\n");
1344                 return;
1345         }
1346
1347         if (host_client->netconnection)
1348         {
1349                 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1350                 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1351                 MSG_WriteByte (&host_client->netconnection->message, 2);
1352         }
1353
1354         // reset the name change timer because the client will send name soon
1355         host_client->nametime = 0;
1356 }
1357
1358 /*
1359 ==================
1360 Host_Spawn_f
1361 ==================
1362 */
1363 void Host_Spawn_f (void)
1364 {
1365         int i;
1366         client_t *client;
1367         func_t RestoreGame;
1368         mfunction_t *f;
1369         int stats[MAX_CL_STATS];
1370
1371         if (cmd_source == src_command)
1372         {
1373                 Con_Print("spawn is not valid from the console\n");
1374                 return;
1375         }
1376
1377         if (host_client->spawned)
1378         {
1379                 Con_Print("Spawn not valid -- already spawned\n");
1380                 return;
1381         }
1382
1383         // reset name change timer again because they might want to change name
1384         // again in the first 5 seconds after connecting
1385         host_client->nametime = 0;
1386
1387         // LordHavoc: moved this above the QC calls at FrikaC's request
1388         // LordHavoc: commented this out
1389         //if (host_client->netconnection)
1390         //      SZ_Clear (&host_client->netconnection->message);
1391
1392         // run the entrance script
1393         if (sv.loadgame)
1394         {
1395                 // loaded games are fully initialized already
1396                 // if this is the last client to be connected, unpause
1397                 sv.paused = false;
1398
1399                 if ((f = PRVM_ED_FindFunction ("RestoreGame")))
1400                 if ((RestoreGame = (func_t)(f - prog->functions)))
1401                 {
1402                         Con_DPrint("Calling RestoreGame\n");
1403                         prog->globals.server->time = sv.time;
1404                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1405                         PRVM_ExecuteProgram (RestoreGame, "QC function RestoreGame is missing");
1406                 }
1407         }
1408         else
1409         {
1410                 //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, host_client->edict->netname = %s, host_client->name = %s\n", PRVM_GetString(host_client->edict->fields.server->netname), PRVM_GetString(host_client->edict->fields.server->netname), host_client->name);
1411
1412                 // copy spawn parms out of the client_t
1413                 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1414                         (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1415
1416                 // call the spawn function
1417                 host_client->clientconnectcalled = true;
1418                 prog->globals.server->time = sv.time;
1419                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1420                 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1421
1422                 if ((Sys_DoubleTime() - host_client->connecttime) <= sv.time)
1423                         Con_Printf("%s entered the game\n", host_client->name);
1424
1425                 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1426         }
1427
1428         if (!host_client->netconnection)
1429                 return;
1430
1431         // send time of update
1432         MSG_WriteByte (&host_client->netconnection->message, svc_time);
1433         MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1434
1435         // send all current names, colors, and frag counts
1436         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1437         {
1438                 if (!client->active)
1439                         continue;
1440                 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1441                 MSG_WriteByte (&host_client->netconnection->message, i);
1442                 MSG_WriteString (&host_client->netconnection->message, client->name);
1443                 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1444                 MSG_WriteByte (&host_client->netconnection->message, i);
1445                 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1446                 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1447                 MSG_WriteByte (&host_client->netconnection->message, i);
1448                 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1449         }
1450
1451         // send all current light styles
1452         for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1453         {
1454                 if (sv.lightstyles[i][0])
1455                 {
1456                         MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1457                         MSG_WriteByte (&host_client->netconnection->message, (char)i);
1458                         MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1459                 }
1460         }
1461
1462         // send some stats
1463         MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1464         MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1465         MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1466
1467         MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1468         MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1469         MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1470
1471         MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1472         MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1473         MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1474
1475         MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1476         MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1477         MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1478
1479         // send a fixangle
1480         // Never send a roll angle, because savegames can catch the server
1481         // in a state where it is expecting the client to correct the angle
1482         // and it won't happen if the game was just loaded, so you wind up
1483         // with a permanent head tilt
1484         if (sv.loadgame)
1485         {
1486                 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1487                 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1488                 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1489                 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1490                 sv.loadgame = false; // we're basically done with loading now
1491         }
1492         else
1493         {
1494                 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1495                 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1496                 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1497                 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1498         }
1499
1500         SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1501
1502         MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1503         MSG_WriteByte (&host_client->netconnection->message, 3);
1504 }
1505
1506 /*
1507 ==================
1508 Host_Begin_f
1509 ==================
1510 */
1511 void Host_Begin_f (void)
1512 {
1513         if (cmd_source == src_command)
1514         {
1515                 Con_Print("begin is not valid from the console\n");
1516                 return;
1517         }
1518
1519         Curl_SendRequirements();
1520
1521         host_client->spawned = true;
1522 }
1523
1524 //===========================================================================
1525
1526
1527 /*
1528 ==================
1529 Host_Kick_f
1530
1531 Kicks a user off of the server
1532 ==================
1533 */
1534 void Host_Kick_f (void)
1535 {
1536         char *who;
1537         const char *message = NULL;
1538         client_t *save;
1539         int i;
1540         qboolean byNumber = false;
1541
1542         if (cmd_source != src_command || !sv.active)
1543                 return;
1544
1545         SV_VM_Begin();
1546         save = host_client;
1547
1548         if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1549         {
1550                 i = (int)(atof(Cmd_Argv(2)) - 1);
1551                 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1552                         return;
1553                 byNumber = true;
1554         }
1555         else
1556         {
1557                 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1558                 {
1559                         if (!host_client->active)
1560                                 continue;
1561                         if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1562                                 break;
1563                 }
1564         }
1565
1566         if (i < svs.maxclients)
1567         {
1568                 if (cmd_source == src_command)
1569                 {
1570                         if (cls.state == ca_dedicated)
1571                                 who = "Console";
1572                         else
1573                                 who = cl_name.string;
1574                 }
1575                 else
1576                         who = save->name;
1577
1578                 // can't kick yourself!
1579                 if (host_client == save)
1580                         return;
1581
1582                 if (Cmd_Argc() > 2)
1583                 {
1584                         message = Cmd_Args();
1585                         COM_ParseToken(&message, false);
1586                         if (byNumber)
1587                         {
1588                                 message++;                                                      // skip the #
1589                                 while (*message == ' ')                         // skip white space
1590                                         message++;
1591                                 message += strlen(Cmd_Argv(2)); // skip the number
1592                         }
1593                         while (*message && *message == ' ')
1594                                 message++;
1595                 }
1596                 if (message)
1597                         SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1598                 else
1599                         SV_ClientPrintf("Kicked by %s\n", who);
1600                 SV_DropClient (false); // kicked
1601         }
1602
1603         host_client = save;
1604         SV_VM_End();
1605 }
1606
1607 /*
1608 ===============================================================================
1609
1610 DEBUGGING TOOLS
1611
1612 ===============================================================================
1613 */
1614
1615 /*
1616 ==================
1617 Host_Give_f
1618 ==================
1619 */
1620 void Host_Give_f (void)
1621 {
1622         const char *t;
1623         int v;
1624         prvm_eval_t *val;
1625
1626         if (cmd_source == src_command)
1627         {
1628                 Cmd_ForwardToServer ();
1629                 return;
1630         }
1631
1632         if (!allowcheats)
1633         {
1634                 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1635                 return;
1636         }
1637
1638         t = Cmd_Argv(1);
1639         v = atoi (Cmd_Argv(2));
1640
1641         switch (t[0])
1642         {
1643         case '0':
1644         case '1':
1645         case '2':
1646         case '3':
1647         case '4':
1648         case '5':
1649         case '6':
1650         case '7':
1651         case '8':
1652         case '9':
1653                 // MED 01/04/97 added hipnotic give stuff
1654                 if (gamemode == GAME_HIPNOTIC)
1655                 {
1656                         if (t[0] == '6')
1657                         {
1658                                 if (t[1] == 'a')
1659                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1660                                 else
1661                                         host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1662                         }
1663                         else if (t[0] == '9')
1664                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1665                         else if (t[0] == '0')
1666                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1667                         else if (t[0] >= '2')
1668                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1669                 }
1670                 else
1671                 {
1672                         if (t[0] >= '2')
1673                                 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1674                 }
1675                 break;
1676
1677         case 's':
1678                 if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1)))
1679                         val->_float = v;
1680
1681                 host_client->edict->fields.server->ammo_shells = v;
1682                 break;
1683         case 'n':
1684                 if (gamemode == GAME_ROGUE)
1685                 {
1686                         if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1)))
1687                         {
1688                                 val->_float = v;
1689                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1690                                         host_client->edict->fields.server->ammo_nails = v;
1691                         }
1692                 }
1693                 else
1694                 {
1695                         host_client->edict->fields.server->ammo_nails = v;
1696                 }
1697                 break;
1698         case 'l':
1699                 if (gamemode == GAME_ROGUE)
1700                 {
1701                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails);
1702                         if (val)
1703                         {
1704                                 val->_float = v;
1705                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1706                                         host_client->edict->fields.server->ammo_nails = v;
1707                         }
1708                 }
1709                 break;
1710         case 'r':
1711                 if (gamemode == GAME_ROGUE)
1712                 {
1713                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1);
1714                         if (val)
1715                         {
1716                                 val->_float = v;
1717                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1718                                         host_client->edict->fields.server->ammo_rockets = v;
1719                         }
1720                 }
1721                 else
1722                 {
1723                         host_client->edict->fields.server->ammo_rockets = v;
1724                 }
1725                 break;
1726         case 'm':
1727                 if (gamemode == GAME_ROGUE)
1728                 {
1729                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets);
1730                         if (val)
1731                         {
1732                                 val->_float = v;
1733                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1734                                         host_client->edict->fields.server->ammo_rockets = v;
1735                         }
1736                 }
1737                 break;
1738         case 'h':
1739                 host_client->edict->fields.server->health = v;
1740                 break;
1741         case 'c':
1742                 if (gamemode == GAME_ROGUE)
1743                 {
1744                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1);
1745                         if (val)
1746                         {
1747                                 val->_float = v;
1748                                 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1749                                         host_client->edict->fields.server->ammo_cells = v;
1750                         }
1751                 }
1752                 else
1753                 {
1754                         host_client->edict->fields.server->ammo_cells = v;
1755                 }
1756                 break;
1757         case 'p':
1758                 if (gamemode == GAME_ROGUE)
1759                 {
1760                         val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma);
1761                         if (val)
1762                         {
1763                                 val->_float = v;
1764                                 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1765                                         host_client->edict->fields.server->ammo_cells = v;
1766                         }
1767                 }
1768                 break;
1769         }
1770 }
1771
1772 prvm_edict_t    *FindViewthing (void)
1773 {
1774         int             i;
1775         prvm_edict_t    *e;
1776
1777         for (i=0 ; i<prog->num_edicts ; i++)
1778         {
1779                 e = PRVM_EDICT_NUM(i);
1780                 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
1781                         return e;
1782         }
1783         Con_Print("No viewthing on map\n");
1784         return NULL;
1785 }
1786
1787 /*
1788 ==================
1789 Host_Viewmodel_f
1790 ==================
1791 */
1792 void Host_Viewmodel_f (void)
1793 {
1794         prvm_edict_t    *e;
1795         model_t *m;
1796
1797         if (!sv.active)
1798                 return;
1799
1800         SV_VM_Begin();
1801         e = FindViewthing ();
1802         SV_VM_End();
1803         if (!e)
1804                 return;
1805
1806         m = Mod_ForName (Cmd_Argv(1), false, true, false);
1807         if (!m || !m->loaded || !m->Draw)
1808         {
1809                 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
1810                 return;
1811         }
1812
1813         e->fields.server->frame = 0;
1814         cl.model_precache[(int)e->fields.server->modelindex] = m;
1815 }
1816
1817 /*
1818 ==================
1819 Host_Viewframe_f
1820 ==================
1821 */
1822 void Host_Viewframe_f (void)
1823 {
1824         prvm_edict_t    *e;
1825         int             f;
1826         model_t *m;
1827
1828         if (!sv.active)
1829                 return;
1830
1831         SV_VM_Begin();
1832         e = FindViewthing ();
1833         SV_VM_End();
1834         if (!e)
1835                 return;
1836         m = cl.model_precache[(int)e->fields.server->modelindex];
1837
1838         f = atoi(Cmd_Argv(1));
1839         if (f >= m->numframes)
1840                 f = m->numframes-1;
1841
1842         e->fields.server->frame = f;
1843 }
1844
1845
1846 void PrintFrameName (model_t *m, int frame)
1847 {
1848         if (m->animscenes)
1849                 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
1850         else
1851                 Con_Printf("frame %i\n", frame);
1852 }
1853
1854 /*
1855 ==================
1856 Host_Viewnext_f
1857 ==================
1858 */
1859 void Host_Viewnext_f (void)
1860 {
1861         prvm_edict_t    *e;
1862         model_t *m;
1863
1864         if (!sv.active)
1865                 return;
1866
1867         SV_VM_Begin();
1868         e = FindViewthing ();
1869         SV_VM_End();
1870         if (!e)
1871                 return;
1872         m = cl.model_precache[(int)e->fields.server->modelindex];
1873
1874         e->fields.server->frame = e->fields.server->frame + 1;
1875         if (e->fields.server->frame >= m->numframes)
1876                 e->fields.server->frame = m->numframes - 1;
1877
1878         PrintFrameName (m, (int)e->fields.server->frame);
1879 }
1880
1881 /*
1882 ==================
1883 Host_Viewprev_f
1884 ==================
1885 */
1886 void Host_Viewprev_f (void)
1887 {
1888         prvm_edict_t    *e;
1889         model_t *m;
1890
1891         if (!sv.active)
1892                 return;
1893
1894         SV_VM_Begin();
1895         e = FindViewthing ();
1896         SV_VM_End();
1897         if (!e)
1898                 return;
1899
1900         m = cl.model_precache[(int)e->fields.server->modelindex];
1901
1902         e->fields.server->frame = e->fields.server->frame - 1;
1903         if (e->fields.server->frame < 0)
1904                 e->fields.server->frame = 0;
1905
1906         PrintFrameName (m, (int)e->fields.server->frame);
1907 }
1908
1909 /*
1910 ===============================================================================
1911
1912 DEMO LOOP CONTROL
1913
1914 ===============================================================================
1915 */
1916
1917
1918 /*
1919 ==================
1920 Host_Startdemos_f
1921 ==================
1922 */
1923 void Host_Startdemos_f (void)
1924 {
1925         int             i, c;
1926
1927         if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-demolooponly"))
1928                 return;
1929
1930         c = Cmd_Argc() - 1;
1931         if (c > MAX_DEMOS)
1932         {
1933                 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
1934                 c = MAX_DEMOS;
1935         }
1936         Con_Printf("%i demo(s) in loop\n", c);
1937
1938         for (i=1 ; i<c+1 ; i++)
1939                 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
1940
1941         // LordHavoc: clear the remaining slots
1942         for (;i <= MAX_DEMOS;i++)
1943                 cls.demos[i-1][0] = 0;
1944
1945         if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1946         {
1947                 cls.demonum = 0;
1948                 CL_NextDemo ();
1949         }
1950         else
1951                 cls.demonum = -1;
1952 }
1953
1954
1955 /*
1956 ==================
1957 Host_Demos_f
1958
1959 Return to looping demos
1960 ==================
1961 */
1962 void Host_Demos_f (void)
1963 {
1964         if (cls.state == ca_dedicated)
1965                 return;
1966         if (cls.demonum == -1)
1967                 cls.demonum = 1;
1968         CL_Disconnect_f ();
1969         CL_NextDemo ();
1970 }
1971
1972 /*
1973 ==================
1974 Host_Stopdemo_f
1975
1976 Return to looping demos
1977 ==================
1978 */
1979 void Host_Stopdemo_f (void)
1980 {
1981         if (!cls.demoplayback)
1982                 return;
1983         CL_Disconnect ();
1984         Host_ShutdownServer ();
1985 }
1986
1987 void Host_SendCvar_f (void)
1988 {
1989         int             i;
1990         cvar_t  *c;
1991         client_t *old;
1992
1993         if(Cmd_Argc() != 2)
1994                 return;
1995         if(!(c = Cvar_FindVar(Cmd_Argv(1))) || (c->flags & CVAR_PRIVATE))
1996                 return;
1997         if (cls.state != ca_dedicated)
1998                 Cmd_ForwardStringToServer(va("sentcvar %s %s\n", c->name, c->string));
1999         if(!sv.active)// || !SV_ParseClientCommandQC)
2000                 return;
2001
2002         old = host_client;
2003         if (cls.state != ca_dedicated)
2004                 i = 1;
2005         else
2006                 i = 0;
2007         for(;i<svs.maxclients;i++)
2008                 if(svs.clients[i].active && svs.clients[i].netconnection)
2009                 {
2010                         host_client = &svs.clients[i];
2011                         Host_ClientCommands(va("sendcvar %s\n", c->name));
2012                 }
2013         host_client = old;
2014 }
2015
2016 static void MaxPlayers_f(void)
2017 {
2018         int n;
2019
2020         if (Cmd_Argc() != 2)
2021         {
2022                 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
2023                 return;
2024         }
2025
2026         if (sv.active)
2027         {
2028                 Con_Print("maxplayers can not be changed while a server is running.\n");
2029                 return;
2030         }
2031
2032         n = atoi(Cmd_Argv(1));
2033         n = bound(1, n, MAX_SCOREBOARD);
2034         Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2035
2036         if (svs.clients)
2037                 Mem_Free(svs.clients);
2038         svs.maxclients = n;
2039         svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
2040         if (n == 1)
2041                 Cvar_Set ("deathmatch", "0");
2042         else
2043                 Cvar_Set ("deathmatch", "1");
2044 }
2045
2046 //=============================================================================
2047
2048 // QuakeWorld commands
2049
2050 /*
2051 =====================
2052 Host_Rcon_f
2053
2054   Send the rest of the command line over as
2055   an unconnected command.
2056 =====================
2057 */
2058 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2059 {
2060         int i;
2061         lhnetaddress_t to;
2062         lhnetsocket_t *mysocket;
2063
2064         if (!rcon_password.string || !rcon_password.string[0])
2065         {
2066                 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2067                 return;
2068         }
2069
2070         for (i = 0;rcon_password.string[i];i++)
2071         {
2072                 if (rcon_password.string[i] <= ' ')
2073                 {
2074                         Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2075                         return;
2076                 }
2077         }
2078
2079         if (cls.netcon)
2080                 to = cls.netcon->peeraddress;
2081         else
2082         {
2083                 if (!rcon_address.string[0])
2084                 {
2085                         Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2086                         return;
2087                 }
2088                 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2089         }
2090         mysocket = NetConn_ChooseClientSocketForAddress(&to);
2091         if (mysocket)
2092         {
2093                 // simply put together the rcon packet and send it
2094                 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2095         }
2096 }
2097
2098 /*
2099 ====================
2100 Host_User_f
2101
2102 user <name or userid>
2103
2104 Dump userdata / masterdata for a user
2105 ====================
2106 */
2107 void Host_User_f (void) // credit: taken from QuakeWorld
2108 {
2109         int             uid;
2110         int             i;
2111
2112         if (Cmd_Argc() != 2)
2113         {
2114                 Con_Printf ("Usage: user <username / userid>\n");
2115                 return;
2116         }
2117
2118         uid = atoi(Cmd_Argv(1));
2119
2120         for (i = 0;i < cl.maxclients;i++)
2121         {
2122                 if (!cl.scores[i].name[0])
2123                         continue;
2124                 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2125                 {
2126                         InfoString_Print(cl.scores[i].qw_userinfo);
2127                         return;
2128                 }
2129         }
2130         Con_Printf ("User not in server.\n");
2131 }
2132
2133 /*
2134 ====================
2135 Host_Users_f
2136
2137 Dump userids for all current players
2138 ====================
2139 */
2140 void Host_Users_f (void) // credit: taken from QuakeWorld
2141 {
2142         int             i;
2143         int             c;
2144
2145         c = 0;
2146         Con_Printf ("userid frags name\n");
2147         Con_Printf ("------ ----- ----\n");
2148         for (i = 0;i < cl.maxclients;i++)
2149         {
2150                 if (cl.scores[i].name[0])
2151                 {
2152                         Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2153                         c++;
2154                 }
2155         }
2156
2157         Con_Printf ("%i total users\n", c);
2158 }
2159
2160 /*
2161 ==================
2162 Host_FullServerinfo_f
2163
2164 Sent by server when serverinfo changes
2165 ==================
2166 */
2167 // TODO: shouldn't this be a cvar instead?
2168 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2169 {
2170         char temp[512];
2171         if (Cmd_Argc() != 2)
2172         {
2173                 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2174                 return;
2175         }
2176
2177         strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2178         InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2179         cl.qw_teamplay = atoi(temp);
2180 }
2181
2182 /*
2183 ==================
2184 Host_FullInfo_f
2185
2186 Allow clients to change userinfo
2187 ==================
2188 Casey was here :)
2189 */
2190 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2191 {
2192         char key[512];
2193         char value[512];
2194         char *o;
2195         const char *s;
2196
2197         if (Cmd_Argc() != 2)
2198         {
2199                 Con_Printf ("fullinfo <complete info string>\n");
2200                 return;
2201         }
2202
2203         s = Cmd_Argv(1);
2204         if (*s == '\\')
2205                 s++;
2206         while (*s)
2207         {
2208                 o = key;
2209                 while (*s && *s != '\\')
2210                         *o++ = *s++;
2211                 *o = 0;
2212
2213                 if (!*s)
2214                 {
2215                         Con_Printf ("MISSING VALUE\n");
2216                         return;
2217                 }
2218
2219                 o = value;
2220                 s++;
2221                 while (*s && *s != '\\')
2222                         *o++ = *s++;
2223                 *o = 0;
2224
2225                 if (*s)
2226                         s++;
2227
2228                 CL_SetInfo(key, value, false, false, false, false);
2229         }
2230 }
2231
2232 /*
2233 ==================
2234 CL_SetInfo_f
2235
2236 Allow clients to change userinfo
2237 ==================
2238 */
2239 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2240 {
2241         if (Cmd_Argc() == 1)
2242         {
2243                 InfoString_Print(cls.userinfo);
2244                 return;
2245         }
2246         if (Cmd_Argc() != 3)
2247         {
2248                 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2249                 return;
2250         }
2251         CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2252 }
2253
2254 /*
2255 ====================
2256 Host_Packet_f
2257
2258 packet <destination> <contents>
2259
2260 Contents allows \n escape character
2261 ====================
2262 */
2263 void Host_Packet_f (void) // credit: taken from QuakeWorld
2264 {
2265         char send[2048];
2266         int i, l;
2267         const char *in;
2268         char *out;
2269         lhnetaddress_t address;
2270         lhnetsocket_t *mysocket;
2271
2272         if (Cmd_Argc() != 3)
2273         {
2274                 Con_Printf ("packet <destination> <contents>\n");
2275                 return;
2276         }
2277
2278         if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2279         {
2280                 Con_Printf ("Bad address\n");
2281                 return;
2282         }
2283
2284         in = Cmd_Argv(2);
2285         out = send+4;
2286         send[0] = send[1] = send[2] = send[3] = 0xff;
2287
2288         l = (int)strlen (in);
2289         for (i=0 ; i<l ; i++)
2290         {
2291                 if (out >= send + sizeof(send) - 1)
2292                         break;
2293                 if (in[i] == '\\' && in[i+1] == 'n')
2294                 {
2295                         *out++ = '\n';
2296                         i++;
2297                 }
2298                 else if (in[i] == '\\' && in[i+1] == '0')
2299                 {
2300                         *out++ = '\0';
2301                         i++;
2302                 }
2303                 else if (in[i] == '\\' && in[i+1] == 't')
2304                 {
2305                         *out++ = '\t';
2306                         i++;
2307                 }
2308                 else if (in[i] == '\\' && in[i+1] == 'r')
2309                 {
2310                         *out++ = '\r';
2311                         i++;
2312                 }
2313                 else if (in[i] == '\\' && in[i+1] == '"')
2314                 {
2315                         *out++ = '\"';
2316                         i++;
2317                 }
2318                 else
2319                         *out++ = in[i];
2320         }
2321
2322         mysocket = NetConn_ChooseClientSocketForAddress(&address);
2323         if (mysocket)
2324                 NetConn_Write(mysocket, send, out - send, &address);
2325 }
2326
2327 //=============================================================================
2328
2329 /*
2330 ==================
2331 Host_InitCommands
2332 ==================
2333 */
2334 void Host_InitCommands (void)
2335 {
2336         dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\%s", engineversion);
2337
2338         Cmd_AddCommand ("status", Host_Status_f, "print server status information");
2339         Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2340         if (gamemode == GAME_NEHAHRA)
2341         {
2342                 Cmd_AddCommand ("max", Host_God_f, "god mode (invulnerability)");
2343                 Cmd_AddCommand ("monster", Host_Notarget_f, "notarget mode (monsters do not see you)");
2344                 Cmd_AddCommand ("scrag", Host_Fly_f, "fly mode (flight)");
2345                 Cmd_AddCommand ("wraith", Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2346                 Cmd_AddCommand ("gimme", Host_Give_f, "alter inventory");
2347         }
2348         else
2349         {
2350                 Cmd_AddCommand ("god", Host_God_f, "god mode (invulnerability)");
2351                 Cmd_AddCommand ("notarget", Host_Notarget_f, "notarget mode (monsters do not see you)");
2352                 Cmd_AddCommand ("fly", Host_Fly_f, "fly mode (flight)");
2353                 Cmd_AddCommand ("noclip", Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2354                 Cmd_AddCommand ("give", Host_Give_f, "alter inventory");
2355         }
2356         Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2357         Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2358         Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2359         Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2360         Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reset signon level in preparation for a new level (do not use)");
2361         Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2362         Cmd_AddCommand ("say", Host_Say_f, "send a chat message to everyone on the server");
2363         Cmd_AddCommand ("say_team", Host_Say_Team_f, "send a chat message to your team on the server");
2364         Cmd_AddCommand ("tell", Host_Tell_f, "send a chat message to only one person on the server");
2365         Cmd_AddCommand ("kill", Host_Kill_f, "die instantly");
2366         Cmd_AddCommand ("pause", Host_Pause_f, "pause the game (if the server allows pausing)");
2367         Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2368         Cmd_AddCommand ("ping", Host_Ping_f, "print ping times of all players on the server");
2369         Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2370         Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2371
2372         Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2373         Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2374         Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2375
2376         Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2377         Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2378         Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2379         Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2380
2381         Cvar_RegisterVariable (&cl_name);
2382         Cmd_AddCommand ("name", Host_Name_f, "change your player name");
2383         Cvar_RegisterVariable (&cl_color);
2384         Cmd_AddCommand ("color", Host_Color_f, "change your player shirt and pants colors");
2385         Cvar_RegisterVariable (&cl_rate);
2386         Cmd_AddCommand ("rate", Host_Rate_f, "change your network connection speed");
2387         if (gamemode == GAME_NEHAHRA)
2388         {
2389                 Cvar_RegisterVariable (&cl_pmodel);
2390                 Cmd_AddCommand ("pmodel", Host_PModel_f, "change your player model choice (Nehahra specific)");
2391         }
2392
2393         // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2394         Cvar_RegisterVariable (&cl_playermodel);
2395         Cmd_AddCommand ("playermodel", Host_Playermodel_f, "change your player model");
2396         Cvar_RegisterVariable (&cl_playerskin);
2397         Cmd_AddCommand ("playerskin", Host_Playerskin_f, "change your player skin number");
2398
2399         Cmd_AddCommand ("prespawn", Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2400         Cmd_AddCommand ("spawn", Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2401         Cmd_AddCommand ("begin", Host_Begin_f, "signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)");
2402         Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2403
2404         Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");       // By [515]
2405
2406         Cvar_RegisterVariable (&rcon_password);
2407         Cvar_RegisterVariable (&rcon_address);
2408         Cmd_AddCommand ("rcon", Host_Rcon_f, "sends a command to the server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's)");
2409         Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2410         Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2411         Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2412         Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2413         Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2414         Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2415         Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2416         Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2417
2418         Cvar_RegisterVariable (&team);
2419         Cvar_RegisterVariable (&skin);
2420         Cvar_RegisterVariable (&noaim);
2421
2422         Cvar_RegisterVariable(&sv_cheats);
2423 }
2424