2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
25 // for secure rcon authentication
31 cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
32 cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
33 cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
34 cvar_t sv_status_show_qcstatus = {CVAR_SAVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."};
35 cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
36 cvar_t rcon_secure = {CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
37 cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
38 cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
39 cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
40 cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
41 cvar_t r_fixtrans_auto = {0, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"};
42 qboolean allowcheats = false;
44 extern qboolean host_shuttingdown;
45 extern cvar_t developer_entityparsing;
53 void Host_Quit_f (void)
56 Con_Printf("shutting down already!\n");
66 void Host_Status_f (void)
70 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
71 void (*print) (const char *fmt, ...);
75 if (cmd_source == src_command)
77 // if running a client, try to send over network so the client's status report parser will see the report
78 if (cls.state == ca_connected)
80 Cmd_ForwardToServer ();
86 print = SV_ClientPrintf;
91 if(cmd_source == src_command)
97 if (strcmp(Cmd_Argv(1), "1") == 0)
99 else if (strcmp(Cmd_Argv(1), "2") == 0)
103 for (players = 0, i = 0;i < svs.maxclients;i++)
104 if (svs.clients[i].active)
106 print ("host: %s\n", Cvar_VariableString ("hostname"));
107 print ("version: %s build %s\n", gamename, buildstring);
108 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
109 print ("map: %s\n", sv.name);
110 print ("timing: %s\n", Host_TimingReport());
111 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
114 print ("^2IP %%pl ping time frags no name\n");
116 print ("^5IP no name\n");
118 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
125 if (in == 0 || in == 1)
127 seconds = (int)(realtime - client->connecttime);
128 minutes = seconds / 60;
131 seconds -= (minutes * 60);
132 hours = minutes / 60;
134 minutes -= (hours * 60);
140 if (client->netconnection)
141 for (j = 0;j < NETGRAPH_PACKETS;j++)
142 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
144 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
145 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
148 if(sv_status_privacy.integer && cmd_source != src_command)
149 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
151 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
153 frags = client->frags;
155 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
157 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
163 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
164 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
168 frags = atoi(qcstatus);
172 if (in == 0) // default layout
174 print ("#%-3u ", i+1);
175 print ("%-16.16s ", client->name);
176 print ("%4i ", frags);
177 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
180 else if (in == 1) // extended layout
182 k%2 ? print("^3") : print("^7");
183 print ("%-21s ", ip);
184 print ("%2i ", packetloss);
185 print ("%4i ", ping);
186 print ("%2i:%02i:%02i ", hours, minutes, seconds);
187 print ("%4i ", frags);
188 print ("#%-3u ", i+1);
189 print ("^7%s\n", client->name);
191 else if (in == 2) // reduced layout
193 k%2 ? print("^3") : print("^7");
194 print ("%-21s ", ip);
195 print ("#%-3u ", i+1);
196 print ("^7%s\n", client->name);
200 if(cmd_source == src_command)
209 Sets client to godmode
212 void Host_God_f (void)
216 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
220 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
221 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
222 SV_ClientPrint("godmode OFF\n");
224 SV_ClientPrint("godmode ON\n");
227 void Host_Notarget_f (void)
231 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
235 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
236 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
237 SV_ClientPrint("notarget OFF\n");
239 SV_ClientPrint("notarget ON\n");
242 qboolean noclip_anglehack;
244 void Host_Noclip_f (void)
248 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
252 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
254 noclip_anglehack = true;
255 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
256 SV_ClientPrint("noclip ON\n");
260 noclip_anglehack = false;
261 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
262 SV_ClientPrint("noclip OFF\n");
270 Sets client to flymode
273 void Host_Fly_f (void)
277 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
281 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
283 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
284 SV_ClientPrint("flymode ON\n");
288 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
289 SV_ClientPrint("flymode OFF\n");
300 void Host_Pings_f (void); // called by Host_Ping_f
301 void Host_Ping_f (void)
305 void (*print) (const char *fmt, ...);
307 if (cmd_source == src_command)
309 // if running a client, try to send over network so the client's ping report parser will see the report
310 if (cls.state == ca_connected)
312 Cmd_ForwardToServer ();
318 print = SV_ClientPrintf;
323 print("Client ping times:\n");
324 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
328 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
331 // now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report)
332 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
337 ===============================================================================
341 ===============================================================================
345 ======================
350 command from the console. Active clients are kicked off.
351 ======================
353 void Host_Map_f (void)
355 char level[MAX_QPATH];
359 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
363 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
364 if (gamemode == GAME_DELUXEQUAKE)
365 Cvar_Set("warpmark", "");
367 cls.demonum = -1; // stop demo loop in case this fails
370 Host_ShutdownServer();
372 if(svs.maxclients != svs.maxclients_next)
374 svs.maxclients = svs.maxclients_next;
376 Mem_Free(svs.clients);
377 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
383 svs.serverflags = 0; // haven't completed an episode yet
384 allowcheats = sv_cheats.integer != 0;
385 strlcpy(level, Cmd_Argv(1), sizeof(level));
386 SV_SpawnServer(level);
387 if (sv.active && cls.state == ca_disconnected)
388 CL_EstablishConnection("local:1");
395 Goes to a new map, taking all clients along
398 void Host_Changelevel_f (void)
400 char level[MAX_QPATH];
404 Con_Print("changelevel <levelname> : continue game on a new level\n");
417 SV_SaveSpawnparms ();
419 allowcheats = sv_cheats.integer != 0;
420 strlcpy(level, Cmd_Argv(1), sizeof(level));
421 SV_SpawnServer(level);
422 if (sv.active && cls.state == ca_disconnected)
423 CL_EstablishConnection("local:1");
430 Restarts the current server for a dead player
433 void Host_Restart_f (void)
435 char mapname[MAX_QPATH];
439 Con_Print("restart : restart current level\n");
444 Con_Print("Only the server may restart\n");
451 allowcheats = sv_cheats.integer != 0;
452 strlcpy(mapname, sv.name, sizeof(mapname));
453 SV_SpawnServer(mapname);
454 if (sv.active && cls.state == ca_disconnected)
455 CL_EstablishConnection("local:1");
462 This command causes the client to wait for the signon messages again.
463 This is sent just before a server changes levels
466 void Host_Reconnect_f (void)
469 // if not connected, reconnect to the most recent server
472 // if we have connected to a server recently, the userinfo
473 // will still contain its IP address, so get the address...
474 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
476 CL_EstablishConnection(temp);
478 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
481 // if connected, do something based on protocol
482 if (cls.protocol == PROTOCOL_QUAKEWORLD)
484 // quakeworld can just re-login
485 if (cls.qw_downloadmemory) // don't change when downloading
490 if (cls.state == ca_connected && cls.signon < SIGNONS)
492 Con_Printf("reconnecting...\n");
493 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
494 MSG_WriteString(&cls.netcon->message, "new");
499 // netquake uses reconnect on level changes (silly)
502 Con_Print("reconnect : wait for signon messages again\n");
507 Con_Print("reconnect: no signon, ignoring reconnect\n");
510 cls.signon = 0; // need new connection messages
515 =====================
518 User command to connect to server
519 =====================
521 void Host_Connect_f (void)
525 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
528 // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
529 if(!rcon_secure.integer)
530 Cvar_SetQuick(&rcon_password, "");
531 CL_EstablishConnection(Cmd_Argv(1));
536 ===============================================================================
540 ===============================================================================
543 #define SAVEGAME_VERSION 5
545 void Host_Savegame_to (const char *name)
548 int i, lightstyles = 64;
549 char comment[SAVEGAME_COMMENT_LENGTH+1];
552 // first we have to figure out if this can be saved in 64 lightstyles
553 // (for Quake compatibility)
554 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
555 if (sv.lightstyles[i][0])
558 isserver = !strcmp(PRVM_NAME, "server");
560 Con_Printf("Saving game to %s...\n", name);
561 f = FS_OpenRealFile(name, "wb", false);
564 Con_Print("ERROR: couldn't open.\n");
568 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
570 memset(comment, 0, sizeof(comment));
572 dpsnprintf(comment, sizeof(comment), "%-21.21s kills:%3i/%3i", PRVM_GetString(prog->edicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters);
574 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
575 // convert space to _ to make stdio happy
576 // LordHavoc: convert control characters to _ as well
577 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
578 if (ISWHITESPACEORCONTROL(comment[i]))
580 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
582 FS_Printf(f, "%s\n", comment);
585 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
586 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
587 FS_Printf(f, "%d\n", current_skill);
588 FS_Printf(f, "%s\n", sv.name);
589 FS_Printf(f, "%f\n",sv.time);
593 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
594 FS_Printf(f, "(dummy)\n");
595 FS_Printf(f, "%d\n", 0);
596 FS_Printf(f, "%s\n", "(dummy)");
597 FS_Printf(f, "%f\n", realtime);
600 // write the light styles
601 for (i=0 ; i<lightstyles ; i++)
603 if (isserver && sv.lightstyles[i][0])
604 FS_Printf(f, "%s\n", sv.lightstyles[i]);
609 PRVM_ED_WriteGlobals (f);
610 for (i=0 ; i<prog->num_edicts ; i++)
612 FS_Printf(f,"// edict %d\n", i);
613 //Con_Printf("edict %d...\n", i);
614 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
619 FS_Printf(f,"// DarkPlaces extended savegame\n");
620 // darkplaces extension - extra lightstyles, support for color lightstyles
621 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
622 if (isserver && sv.lightstyles[i][0])
623 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
625 // darkplaces extension - model precaches
626 for (i=1 ; i<MAX_MODELS ; i++)
627 if (sv.model_precache[i][0])
628 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
630 // darkplaces extension - sound precaches
631 for (i=1 ; i<MAX_SOUNDS ; i++)
632 if (sv.sound_precache[i][0])
633 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
638 Con_Print("done.\n");
646 void Host_Savegame_f (void)
648 char name[MAX_QPATH];
652 Con_Print("Can't save - no server running.\n");
658 // singleplayer checks
661 Con_Print("Can't save in intermission.\n");
665 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
667 Con_Print("Can't savegame with a dead player\n");
672 Con_Print("Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n");
676 Con_Print("save <savename> : save a game\n");
680 if (strstr(Cmd_Argv(1), ".."))
682 Con_Print("Relative pathnames are not allowed.\n");
686 strlcpy (name, Cmd_Argv(1), sizeof (name));
687 FS_DefaultExtension (name, ".sav", sizeof (name));
690 Host_Savegame_to(name);
700 void Host_Loadgame_f (void)
702 char filename[MAX_QPATH];
703 char mapname[MAX_QPATH];
713 float spawn_parms[NUM_SPAWN_PARMS];
717 Con_Print("load <savename> : load a game\n");
721 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
722 FS_DefaultExtension (filename, ".sav", sizeof (filename));
724 Con_Printf("Loading game from %s...\n", filename);
726 // stop playing demos
727 if (cls.demoplayback)
733 cls.demonum = -1; // stop demo loop in case this fails
735 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
738 Con_Print("ERROR: couldn't open.\n");
742 if(developer_entityparsing.integer)
743 Con_Printf("Host_Loadgame_f: loading version\n");
746 COM_ParseToken_Simple(&t, false, false);
747 version = atoi(com_token);
748 if (version != SAVEGAME_VERSION)
751 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
755 if(developer_entityparsing.integer)
756 Con_Printf("Host_Loadgame_f: loading description\n");
759 COM_ParseToken_Simple(&t, false, false);
761 for (i = 0;i < NUM_SPAWN_PARMS;i++)
763 COM_ParseToken_Simple(&t, false, false);
764 spawn_parms[i] = atof(com_token);
767 COM_ParseToken_Simple(&t, false, false);
768 // this silliness is so we can load 1.06 save files, which have float skill values
769 current_skill = (int)(atof(com_token) + 0.5);
770 Cvar_SetValue ("skill", (float)current_skill);
772 if(developer_entityparsing.integer)
773 Con_Printf("Host_Loadgame_f: loading mapname\n");
776 COM_ParseToken_Simple(&t, false, false);
777 strlcpy (mapname, com_token, sizeof(mapname));
779 if(developer_entityparsing.integer)
780 Con_Printf("Host_Loadgame_f: loading time\n");
783 COM_ParseToken_Simple(&t, false, false);
784 time = atof(com_token);
786 allowcheats = sv_cheats.integer != 0;
788 if(developer_entityparsing.integer)
789 Con_Printf("Host_Loadgame_f: spawning server\n");
791 SV_SpawnServer (mapname);
795 Con_Print("Couldn't load map\n");
798 sv.paused = true; // pause until all clients connect
801 if(developer_entityparsing.integer)
802 Con_Printf("Host_Loadgame_f: loading light styles\n");
804 // load the light styles
810 for (i = 0;i < MAX_LIGHTSTYLES;i++)
814 COM_ParseToken_Simple(&t, false, false);
815 // if this is a 64 lightstyle savegame produced by Quake, stop now
816 // we have to check this because darkplaces may save more than 64
817 if (com_token[0] == '{')
822 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
825 if(developer_entityparsing.integer)
826 Con_Printf("Host_Loadgame_f: skipping until globals\n");
828 // now skip everything before the first opening brace
829 // (this is for forward compatibility, so that older versions (at
830 // least ones with this fix) can load savegames with extra data before the
831 // first brace, as might be produced by a later engine version)
835 if (!COM_ParseToken_Simple(&t, false, false))
837 if (com_token[0] == '{')
844 // load the edicts out of the savegame file
849 while (COM_ParseToken_Simple(&t, false, false))
850 if (!strcmp(com_token, "}"))
852 if (!COM_ParseToken_Simple(&start, false, false))
857 if (strcmp(com_token,"{"))
860 Host_Error ("First token isn't a brace");
865 if(developer_entityparsing.integer)
866 Con_Printf("Host_Loadgame_f: loading globals\n");
868 // parse the global vars
869 PRVM_ED_ParseGlobals (start);
874 if (entnum >= MAX_EDICTS)
877 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
879 while (entnum >= prog->max_edicts)
880 PRVM_MEM_IncreaseEdicts();
881 ent = PRVM_EDICT_NUM(entnum);
882 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
883 ent->priv.server->free = false;
885 if(developer_entityparsing.integer)
886 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
888 PRVM_ED_ParseEdict (start, ent);
890 // link it into the bsp tree
891 if (!ent->priv.server->free)
892 SV_LinkEdict (ent, false);
899 prog->num_edicts = entnum;
902 for (i = 0;i < NUM_SPAWN_PARMS;i++)
903 svs.clients[0].spawn_parms[i] = spawn_parms[i];
905 if(developer_entityparsing.integer)
906 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
908 // read extended data if present
909 // the extended data is stored inside a /* */ comment block, which the
910 // parser intentionally skips, so we have to check for it manually here
913 while (*end == '\r' || *end == '\n')
915 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
917 if(developer_entityparsing.integer)
918 Con_Printf("Host_Loadgame_f: loading extended data\n");
920 Con_Printf("Loading extended DarkPlaces savegame\n");
922 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
923 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
924 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
925 while (COM_ParseToken_Simple(&t, false, false))
927 if (!strcmp(com_token, "sv.lightstyles"))
929 COM_ParseToken_Simple(&t, false, false);
931 COM_ParseToken_Simple(&t, false, false);
932 if (i >= 0 && i < MAX_LIGHTSTYLES)
933 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
935 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
937 else if (!strcmp(com_token, "sv.model_precache"))
939 COM_ParseToken_Simple(&t, false, false);
941 COM_ParseToken_Simple(&t, false, false);
942 if (i >= 0 && i < MAX_MODELS)
944 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
945 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL);
948 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
950 else if (!strcmp(com_token, "sv.sound_precache"))
952 COM_ParseToken_Simple(&t, false, false);
954 COM_ParseToken_Simple(&t, false, false);
955 if (i >= 0 && i < MAX_SOUNDS)
956 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
958 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
960 // skip any trailing text or unrecognized commands
961 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
968 if(developer_entityparsing.integer)
969 Con_Printf("Host_Loadgame_f: finished\n");
973 // make sure we're connected to loopback
974 if (sv.active && cls.state == ca_disconnected)
975 CL_EstablishConnection("local:1");
978 //============================================================================
981 ======================
983 ======================
985 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
986 void Host_Name_f (void)
989 qboolean valid_colors;
990 char newName[sizeof(host_client->name)];
992 if (Cmd_Argc () == 1)
994 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
998 if (Cmd_Argc () == 2)
999 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
1001 strlcpy (newName, Cmd_Args(), sizeof (newName));
1003 if (cmd_source == src_command)
1005 Cvar_Set ("_cl_name", newName);
1009 if (realtime < host_client->nametime)
1011 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1015 host_client->nametime = realtime + 5;
1017 // point the string back at updateclient->name to keep it safe
1018 strlcpy (host_client->name, newName, sizeof (host_client->name));
1020 for (i = 0, j = 0;host_client->name[i];i++)
1021 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1022 host_client->name[j++] = host_client->name[i];
1023 host_client->name[j] = 0;
1025 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1026 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1028 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1029 host_client->name[sizeof(host_client->name) - 1] = 0;
1030 host_client->name[0] = STRING_COLOR_TAG;
1031 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1034 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1035 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1038 l = strlen(host_client->name);
1039 if(l < sizeof(host_client->name) - 1)
1041 // duplicate the color tag to escape it
1042 host_client->name[i] = STRING_COLOR_TAG;
1043 host_client->name[i+1] = 0;
1044 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1048 // remove the last character to fix the color code
1049 host_client->name[l-1] = 0;
1050 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1054 // find the last color tag offset and decide if we need to add a reset tag
1055 for (i = 0, j = -1;host_client->name[i];i++)
1057 if (host_client->name[i] == STRING_COLOR_TAG)
1059 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1062 // if this happens to be a reset tag then we don't need one
1063 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1068 if (host_client->name[i+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4]))
1074 if (host_client->name[i+1] == STRING_COLOR_TAG)
1081 // does not end in the default color string, so add it
1082 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1083 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1085 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1086 if (strcmp(host_client->old_name, host_client->name))
1088 if (host_client->spawned)
1089 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1090 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1091 // send notification to all clients
1092 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1093 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1094 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1095 SV_WriteNetnameIntoDemo(host_client);
1100 ======================
1102 ======================
1104 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1105 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1106 void Host_Playermodel_f (void)
1109 char newPath[sizeof(host_client->playermodel)];
1111 if (Cmd_Argc () == 1)
1113 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1117 if (Cmd_Argc () == 2)
1118 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1120 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1122 for (i = 0, j = 0;newPath[i];i++)
1123 if (newPath[i] != '\r' && newPath[i] != '\n')
1124 newPath[j++] = newPath[i];
1127 if (cmd_source == src_command)
1129 Cvar_Set ("_cl_playermodel", newPath);
1134 if (realtime < host_client->nametime)
1136 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1140 host_client->nametime = realtime + 5;
1143 // point the string back at updateclient->name to keep it safe
1144 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1145 if( prog->fieldoffsets.playermodel >= 0 )
1146 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1147 if (strcmp(host_client->old_model, host_client->playermodel))
1149 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1150 /*// send notification to all clients
1151 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1152 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1153 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1158 ======================
1160 ======================
1162 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1163 void Host_Playerskin_f (void)
1166 char newPath[sizeof(host_client->playerskin)];
1168 if (Cmd_Argc () == 1)
1170 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1174 if (Cmd_Argc () == 2)
1175 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1177 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1179 for (i = 0, j = 0;newPath[i];i++)
1180 if (newPath[i] != '\r' && newPath[i] != '\n')
1181 newPath[j++] = newPath[i];
1184 if (cmd_source == src_command)
1186 Cvar_Set ("_cl_playerskin", newPath);
1191 if (realtime < host_client->nametime)
1193 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1197 host_client->nametime = realtime + 5;
1200 // point the string back at updateclient->name to keep it safe
1201 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1202 if( prog->fieldoffsets.playerskin >= 0 )
1203 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1204 if (strcmp(host_client->old_skin, host_client->playerskin))
1206 //if (host_client->spawned)
1207 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1208 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1209 /*// send notification to all clients
1210 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1211 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1212 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1216 void Host_Version_f (void)
1218 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1221 void Host_Say(qboolean teamonly)
1227 // LordHavoc: long say messages
1229 qboolean fromServer = false;
1231 if (cmd_source == src_command)
1233 if (cls.state == ca_dedicated)
1240 Cmd_ForwardToServer ();
1245 if (Cmd_Argc () < 2)
1248 if (!teamplay.integer)
1258 // note this uses the chat prefix \001
1259 if (!fromServer && !teamonly)
1260 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1261 else if (!fromServer && teamonly)
1262 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1263 else if(*(sv_adminnick.string))
1264 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1266 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1267 p2 = text + strlen(text);
1268 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1270 if (p2[-1] == '\"' && quoted)
1275 strlcat(text, "\n", sizeof(text));
1277 // note: save is not a valid edict if fromServer is true
1279 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1280 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1281 SV_ClientPrint(text);
1284 if (cls.state == ca_dedicated)
1285 Con_Print(&text[1]);
1289 void Host_Say_f(void)
1295 void Host_Say_Team_f(void)
1301 void Host_Tell_f(void)
1303 const char *playername_start = NULL;
1304 size_t playername_length = 0;
1305 int playernumber = 0;
1308 const char *p1, *p2;
1309 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1310 qboolean fromServer = false;
1312 if (cmd_source == src_command)
1314 if (cls.state == ca_dedicated)
1318 Cmd_ForwardToServer ();
1323 if (Cmd_Argc () < 2)
1326 // note this uses the chat prefix \001
1328 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1329 else if(*(sv_adminnick.string))
1330 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1332 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1335 p2 = p1 + strlen(p1);
1336 // remove the target name
1337 while (p1 < p2 && *p1 == ' ')
1342 while (p1 < p2 && *p1 == ' ')
1344 while (p1 < p2 && isdigit(*p1))
1346 playernumber = playernumber * 10 + (*p1 - '0');
1354 playername_start = p1;
1355 while (p1 < p2 && *p1 != '"')
1357 playername_length = p1 - playername_start;
1363 playername_start = p1;
1364 while (p1 < p2 && *p1 != ' ')
1366 playername_length = p1 - playername_start;
1368 while (p1 < p2 && *p1 == ' ')
1370 if(playername_start)
1372 // set playernumber to the right client
1374 if(playername_length >= sizeof(namebuf))
1377 Con_Print("Host_Tell: too long player name/ID\n");
1379 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1382 memcpy(namebuf, playername_start, playername_length);
1383 namebuf[playername_length] = 0;
1384 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1386 if (!svs.clients[playernumber].active)
1388 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1392 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1395 Con_Print("Host_Tell: invalid player name/ID\n");
1397 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1400 // remove trailing newlines
1401 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1403 // remove quotes if present
1409 else if (fromServer)
1410 Con_Print("Host_Tell: missing end quote\n");
1412 SV_ClientPrint("Host_Tell: missing end quote\n");
1414 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1417 return; // empty say
1418 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1424 host_client = svs.clients + playernumber;
1425 SV_ClientPrint(text);
1435 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1436 void Host_Color(int changetop, int changebottom)
1438 int top, bottom, playercolor;
1440 // get top and bottom either from the provided values or the current values
1441 // (allows changing only top or bottom, or both at once)
1442 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1443 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1447 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1453 playercolor = top*16 + bottom;
1455 if (cmd_source == src_command)
1457 Cvar_SetValueQuick(&cl_color, playercolor);
1461 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1464 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1466 Con_DPrint("Calling SV_ChangeTeam\n");
1467 prog->globals.server->time = sv.time;
1468 prog->globals.generic[OFS_PARM0] = playercolor;
1469 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1470 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1475 if (host_client->edict)
1477 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1478 val->_float = playercolor;
1479 host_client->edict->fields.server->team = bottom + 1;
1481 host_client->colors = playercolor;
1482 if (host_client->old_colors != host_client->colors)
1484 host_client->old_colors = host_client->colors;
1485 // send notification to all clients
1486 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1487 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1488 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1493 void Host_Color_f(void)
1497 if (Cmd_Argc() == 1)
1499 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1500 Con_Print("color <0-15> [0-15]\n");
1504 if (Cmd_Argc() == 2)
1505 top = bottom = atoi(Cmd_Argv(1));
1508 top = atoi(Cmd_Argv(1));
1509 bottom = atoi(Cmd_Argv(2));
1511 Host_Color(top, bottom);
1514 void Host_TopColor_f(void)
1516 if (Cmd_Argc() == 1)
1518 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1519 Con_Print("topcolor <0-15>\n");
1523 Host_Color(atoi(Cmd_Argv(1)), -1);
1526 void Host_BottomColor_f(void)
1528 if (Cmd_Argc() == 1)
1530 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1531 Con_Print("bottomcolor <0-15>\n");
1535 Host_Color(-1, atoi(Cmd_Argv(1)));
1538 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1539 void Host_Rate_f(void)
1543 if (Cmd_Argc() != 2)
1545 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1546 Con_Print("rate <bytespersecond>\n");
1550 rate = atoi(Cmd_Argv(1));
1552 if (cmd_source == src_command)
1554 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1558 host_client->rate = rate;
1566 void Host_Kill_f (void)
1568 if (host_client->edict->fields.server->health <= 0)
1570 SV_ClientPrint("Can't suicide -- already dead!\n");
1574 prog->globals.server->time = sv.time;
1575 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1576 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1585 void Host_Pause_f (void)
1587 if (!pausable.integer)
1588 SV_ClientPrint("Pause not allowed.\n");
1592 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1593 // send notification to all clients
1594 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1595 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1600 ======================
1602 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1603 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1604 ======================
1606 cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
1607 static void Host_PModel_f (void)
1612 if (Cmd_Argc () == 1)
1614 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1617 i = atoi(Cmd_Argv(1));
1619 if (cmd_source == src_command)
1621 if (cl_pmodel.integer == i)
1623 Cvar_SetValue ("_cl_pmodel", i);
1624 if (cls.state == ca_connected)
1625 Cmd_ForwardToServer ();
1629 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1633 //===========================================================================
1641 void Host_PreSpawn_f (void)
1643 if (host_client->spawned)
1645 Con_Print("prespawn not valid -- already spawned\n");
1649 if (host_client->netconnection)
1651 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1652 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1653 MSG_WriteByte (&host_client->netconnection->message, 2);
1654 host_client->sendsignon = 0; // enable unlimited sends again
1657 // reset the name change timer because the client will send name soon
1658 host_client->nametime = 0;
1666 void Host_Spawn_f (void)
1670 int stats[MAX_CL_STATS];
1672 if (host_client->spawned)
1674 Con_Print("Spawn not valid -- already spawned\n");
1678 // reset name change timer again because they might want to change name
1679 // again in the first 5 seconds after connecting
1680 host_client->nametime = 0;
1682 // LordHavoc: moved this above the QC calls at FrikaC's request
1683 // LordHavoc: commented this out
1684 //if (host_client->netconnection)
1685 // SZ_Clear (&host_client->netconnection->message);
1687 // run the entrance script
1690 // loaded games are fully initialized already
1691 if (prog->funcoffsets.RestoreGame)
1693 Con_DPrint("Calling RestoreGame\n");
1694 prog->globals.server->time = sv.time;
1695 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1696 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1701 //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);
1703 // copy spawn parms out of the client_t
1704 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1705 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1707 // call the spawn function
1708 host_client->clientconnectcalled = true;
1709 prog->globals.server->time = sv.time;
1710 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1711 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1713 if (cls.state == ca_dedicated)
1714 Con_Printf("%s connected\n", host_client->name);
1716 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1719 if (!host_client->netconnection)
1722 // send time of update
1723 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1724 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1726 // send all current names, colors, and frag counts
1727 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1729 if (!client->active)
1731 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1732 MSG_WriteByte (&host_client->netconnection->message, i);
1733 MSG_WriteString (&host_client->netconnection->message, client->name);
1734 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1735 MSG_WriteByte (&host_client->netconnection->message, i);
1736 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1737 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1738 MSG_WriteByte (&host_client->netconnection->message, i);
1739 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1742 // send all current light styles
1743 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1745 if (sv.lightstyles[i][0])
1747 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1748 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1749 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1754 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1755 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1756 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1758 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1759 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1760 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1762 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1763 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1764 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1766 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1767 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1768 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1771 // Never send a roll angle, because savegames can catch the server
1772 // in a state where it is expecting the client to correct the angle
1773 // and it won't happen if the game was just loaded, so you wind up
1774 // with a permanent head tilt
1777 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1778 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1779 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1780 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1784 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1785 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1786 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1787 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1790 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1792 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1793 MSG_WriteByte (&host_client->netconnection->message, 3);
1801 void Host_Begin_f (void)
1803 host_client->spawned = true;
1805 // LordHavoc: note: this code also exists in SV_DropClient
1809 for (i = 0;i < svs.maxclients;i++)
1810 if (svs.clients[i].active && !svs.clients[i].spawned)
1812 if (i == svs.maxclients)
1814 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1815 sv.paused = sv.loadgame = false; // we're basically done with loading now
1820 //===========================================================================
1827 Kicks a user off of the server
1830 void Host_Kick_f (void)
1833 const char *message = NULL;
1836 qboolean byNumber = false;
1844 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1846 i = (int)(atof(Cmd_Argv(2)) - 1);
1847 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1853 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1855 if (!host_client->active)
1857 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1862 if (i < svs.maxclients)
1864 if (cmd_source == src_command)
1866 if (cls.state == ca_dedicated)
1869 who = cl_name.string;
1874 // can't kick yourself!
1875 if (host_client == save)
1880 message = Cmd_Args();
1881 COM_ParseToken_Simple(&message, false, false);
1884 message++; // skip the #
1885 while (*message == ' ') // skip white space
1887 message += strlen(Cmd_Argv(2)); // skip the number
1889 while (*message && *message == ' ')
1893 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1895 SV_ClientPrintf("Kicked by %s\n", who);
1896 SV_DropClient (false); // kicked
1904 ===============================================================================
1908 ===============================================================================
1916 void Host_Give_f (void)
1924 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1929 v = atoi (Cmd_Argv(2));
1943 // MED 01/04/97 added hipnotic give stuff
1944 if (gamemode == GAME_HIPNOTIC)
1949 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1951 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1953 else if (t[0] == '9')
1954 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1955 else if (t[0] == '0')
1956 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1957 else if (t[0] >= '2')
1958 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1963 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1968 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1971 host_client->edict->fields.server->ammo_shells = v;
1974 if (gamemode == GAME_ROGUE)
1976 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1979 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1980 host_client->edict->fields.server->ammo_nails = v;
1985 host_client->edict->fields.server->ammo_nails = v;
1989 if (gamemode == GAME_ROGUE)
1991 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1995 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1996 host_client->edict->fields.server->ammo_nails = v;
2001 if (gamemode == GAME_ROGUE)
2003 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
2007 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2008 host_client->edict->fields.server->ammo_rockets = v;
2013 host_client->edict->fields.server->ammo_rockets = v;
2017 if (gamemode == GAME_ROGUE)
2019 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2023 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2024 host_client->edict->fields.server->ammo_rockets = v;
2029 host_client->edict->fields.server->health = v;
2032 if (gamemode == GAME_ROGUE)
2034 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2038 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2039 host_client->edict->fields.server->ammo_cells = v;
2044 host_client->edict->fields.server->ammo_cells = v;
2048 if (gamemode == GAME_ROGUE)
2050 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2054 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2055 host_client->edict->fields.server->ammo_cells = v;
2062 prvm_edict_t *FindViewthing (void)
2067 for (i=0 ; i<prog->num_edicts ; i++)
2069 e = PRVM_EDICT_NUM(i);
2070 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2073 Con_Print("No viewthing on map\n");
2082 void Host_Viewmodel_f (void)
2091 e = FindViewthing ();
2096 m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
2097 if (!m || !m->loaded || !m->Draw)
2099 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2103 e->fields.server->frame = 0;
2104 cl.model_precache[(int)e->fields.server->modelindex] = m;
2112 void Host_Viewframe_f (void)
2122 e = FindViewthing ();
2126 m = cl.model_precache[(int)e->fields.server->modelindex];
2128 f = atoi(Cmd_Argv(1));
2129 if (f >= m->numframes)
2132 e->fields.server->frame = f;
2136 void PrintFrameName (dp_model_t *m, int frame)
2139 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2141 Con_Printf("frame %i\n", frame);
2149 void Host_Viewnext_f (void)
2158 e = FindViewthing ();
2162 m = cl.model_precache[(int)e->fields.server->modelindex];
2164 e->fields.server->frame = e->fields.server->frame + 1;
2165 if (e->fields.server->frame >= m->numframes)
2166 e->fields.server->frame = m->numframes - 1;
2168 PrintFrameName (m, (int)e->fields.server->frame);
2176 void Host_Viewprev_f (void)
2185 e = FindViewthing ();
2190 m = cl.model_precache[(int)e->fields.server->modelindex];
2192 e->fields.server->frame = e->fields.server->frame - 1;
2193 if (e->fields.server->frame < 0)
2194 e->fields.server->frame = 0;
2196 PrintFrameName (m, (int)e->fields.server->frame);
2200 ===============================================================================
2204 ===============================================================================
2213 void Host_Startdemos_f (void)
2217 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2223 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2226 Con_DPrintf("%i demo(s) in loop\n", c);
2228 for (i=1 ; i<c+1 ; i++)
2229 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2231 // LordHavoc: clear the remaining slots
2232 for (;i <= MAX_DEMOS;i++)
2233 cls.demos[i-1][0] = 0;
2235 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2249 Return to looping demos
2252 void Host_Demos_f (void)
2254 if (cls.state == ca_dedicated)
2256 if (cls.demonum == -1)
2266 Return to looping demos
2269 void Host_Stopdemo_f (void)
2271 if (!cls.demoplayback)
2274 Host_ShutdownServer ();
2277 void Host_SendCvar_f (void)
2281 const char *cvarname;
2286 cvarname = Cmd_Argv(1);
2287 if (cls.state == ca_connected)
2289 c = Cvar_FindVar(cvarname);
2290 // LordHavoc: if there is no such cvar or if it is private, send a
2291 // reply indicating that it has no value
2292 if(!c || (c->flags & CVAR_PRIVATE))
2293 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2295 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2298 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2302 if (cls.state != ca_dedicated)
2306 for(;i<svs.maxclients;i++)
2307 if(svs.clients[i].active && svs.clients[i].netconnection)
2309 host_client = &svs.clients[i];
2310 Host_ClientCommands("sendcvar %s\n", cvarname);
2315 static void MaxPlayers_f(void)
2319 if (Cmd_Argc() != 2)
2321 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
2327 Con_Print("maxplayers can not be changed while a server is running.\n");
2328 Con_Print("It will be changed on next server startup (\"map\" command).\n");
2331 n = atoi(Cmd_Argv(1));
2332 n = bound(1, n, MAX_SCOREBOARD);
2333 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2335 svs.maxclients_next = n;
2337 Cvar_Set ("deathmatch", "0");
2339 Cvar_Set ("deathmatch", "1");
2342 //=============================================================================
2344 // QuakeWorld commands
2347 =====================
2350 Send the rest of the command line over as
2351 an unconnected command.
2352 =====================
2354 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2358 lhnetsocket_t *mysocket;
2360 if (!rcon_password.string || !rcon_password.string[0])
2362 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2366 for (i = 0;rcon_password.string[i];i++)
2368 if (ISWHITESPACE(rcon_password.string[i]))
2370 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2376 to = cls.netcon->peeraddress;
2379 if (!rcon_address.string[0])
2381 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2384 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2386 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2389 // simply put together the rcon packet and send it
2390 if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer)
2394 dpsnprintf(argbuf, sizeof(argbuf), "%ld %s", (long) time(NULL), Cmd_Args());
2395 memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24);
2396 if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, strlen(rcon_password.string)))
2399 strlcpy(buf + 41, argbuf, sizeof(buf) - 41);
2400 NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to);
2405 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2411 ====================
2414 user <name or userid>
2416 Dump userdata / masterdata for a user
2417 ====================
2419 void Host_User_f (void) // credit: taken from QuakeWorld
2424 if (Cmd_Argc() != 2)
2426 Con_Printf ("Usage: user <username / userid>\n");
2430 uid = atoi(Cmd_Argv(1));
2432 for (i = 0;i < cl.maxclients;i++)
2434 if (!cl.scores[i].name[0])
2436 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2438 InfoString_Print(cl.scores[i].qw_userinfo);
2442 Con_Printf ("User not in server.\n");
2446 ====================
2449 Dump userids for all current players
2450 ====================
2452 void Host_Users_f (void) // credit: taken from QuakeWorld
2458 Con_Printf ("userid frags name\n");
2459 Con_Printf ("------ ----- ----\n");
2460 for (i = 0;i < cl.maxclients;i++)
2462 if (cl.scores[i].name[0])
2464 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2469 Con_Printf ("%i total users\n", c);
2474 Host_FullServerinfo_f
2476 Sent by server when serverinfo changes
2479 // TODO: shouldn't this be a cvar instead?
2480 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2483 if (Cmd_Argc() != 2)
2485 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2489 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2490 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2491 cl.qw_teamplay = atoi(temp);
2498 Allow clients to change userinfo
2502 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2509 if (Cmd_Argc() != 2)
2511 Con_Printf ("fullinfo <complete info string>\n");
2521 while (*s && *s != '\\')
2527 Con_Printf ("MISSING VALUE\n");
2533 while (*s && *s != '\\')
2540 CL_SetInfo(key, value, false, false, false, false);
2548 Allow clients to change userinfo
2551 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2553 if (Cmd_Argc() == 1)
2555 InfoString_Print(cls.userinfo);
2558 if (Cmd_Argc() != 3)
2560 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2563 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2567 ====================
2570 packet <destination> <contents>
2572 Contents allows \n escape character
2573 ====================
2575 void Host_Packet_f (void) // credit: taken from QuakeWorld
2581 lhnetaddress_t address;
2582 lhnetsocket_t *mysocket;
2584 if (Cmd_Argc() != 3)
2586 Con_Printf ("packet <destination> <contents>\n");
2590 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2592 Con_Printf ("Bad address\n");
2598 send[0] = send[1] = send[2] = send[3] = 0xff;
2600 l = (int)strlen (in);
2601 for (i=0 ; i<l ; i++)
2603 if (out >= send + sizeof(send) - 1)
2605 if (in[i] == '\\' && in[i+1] == 'n')
2610 else if (in[i] == '\\' && in[i+1] == '0')
2615 else if (in[i] == '\\' && in[i+1] == 't')
2620 else if (in[i] == '\\' && in[i+1] == 'r')
2625 else if (in[i] == '\\' && in[i+1] == '"')
2634 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2636 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2638 NetConn_Write(mysocket, send, out - send, &address);
2642 ====================
2645 Send back ping and packet loss update for all current players to this player
2646 ====================
2648 void Host_Pings_f (void)
2650 int i, j, ping, packetloss;
2653 if (!host_client->netconnection)
2656 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2658 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2659 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2661 for (i = 0;i < svs.maxclients;i++)
2664 if (svs.clients[i].netconnection)
2665 for (j = 0;j < NETGRAPH_PACKETS;j++)
2666 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2668 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2669 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2670 ping = bound(0, ping, 9999);
2671 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2673 // send qw_svc_updateping and qw_svc_updatepl messages
2674 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2675 MSG_WriteShort(&host_client->netconnection->message, ping);
2676 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2677 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2681 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2682 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2683 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2686 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2687 MSG_WriteString(&host_client->netconnection->message, "\n");
2690 void Host_PingPLReport_f(void)
2694 if (l > cl.maxclients)
2696 for (i = 0;i < l;i++)
2698 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2699 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2703 //=============================================================================
2710 void Host_InitCommands (void)
2712 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2714 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2715 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2716 if (gamemode == GAME_NEHAHRA)
2718 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2719 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2720 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2721 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2722 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2726 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2727 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2728 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2729 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2730 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2732 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2733 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2734 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2735 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2736 Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reconnect to the last server you were on, or resets a quakeworld connection (do not use if currently playing on a netquake server)");
2737 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2738 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2739 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2740 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2741 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2742 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2743 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2744 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2745 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2746 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2748 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2749 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2750 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2752 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2753 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2754 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2755 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2757 Cvar_RegisterVariable (&cl_name);
2758 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2759 Cvar_RegisterVariable (&cl_color);
2760 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2761 Cvar_RegisterVariable (&cl_rate);
2762 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2763 if (gamemode == GAME_NEHAHRA)
2765 Cvar_RegisterVariable (&cl_pmodel);
2766 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2769 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2770 Cvar_RegisterVariable (&cl_playermodel);
2771 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2772 Cvar_RegisterVariable (&cl_playerskin);
2773 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2775 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2776 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2777 Cmd_AddCommand_WithClientCommand ("begin", NULL, 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)");
2778 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2780 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2782 Cvar_RegisterVariable (&rcon_password);
2783 Cvar_RegisterVariable (&rcon_address);
2784 Cvar_RegisterVariable (&rcon_secure);
2785 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)");
2786 Cmd_AddCommand ("srcon", 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); this always works as if rcon_secure is set");
2787 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2788 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2789 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2790 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2791 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2792 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2793 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2794 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2796 Cmd_AddCommand_WithClientCommand ("pings", NULL, Host_Pings_f, "command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)");
2797 Cmd_AddCommand ("pingplreport", Host_PingPLReport_f, "command sent by server containing client ping and packet loss values for scoreboard, triggered by pings command from client (not used by QW servers)");
2799 Cmd_AddCommand ("fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)");
2800 Cvar_RegisterVariable (&r_fixtrans_auto);
2802 Cvar_RegisterVariable (&team);
2803 Cvar_RegisterVariable (&skin);
2804 Cvar_RegisterVariable (&noaim);
2806 Cvar_RegisterVariable(&sv_cheats);
2807 Cvar_RegisterVariable(&sv_adminnick);
2808 Cvar_RegisterVariable(&sv_status_privacy);
2809 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2812 void Host_NoOperation_f(void)