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