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));
477 // clear the rcon password, to prevent vulnerability by stuffcmd-ing a setinfo command to change *ip, then reconnect
478 if(!rcon_secure.integer)
479 Cvar_SetQuick(&rcon_password, "");
480 CL_EstablishConnection(temp);
483 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
486 // if connected, do something based on protocol
487 if (cls.protocol == PROTOCOL_QUAKEWORLD)
489 // quakeworld can just re-login
490 if (cls.qw_downloadmemory) // don't change when downloading
495 if (cls.state == ca_connected && cls.signon < SIGNONS)
497 Con_Printf("reconnecting...\n");
498 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
499 MSG_WriteString(&cls.netcon->message, "new");
504 // netquake uses reconnect on level changes (silly)
507 Con_Print("reconnect : wait for signon messages again\n");
512 Con_Print("reconnect: no signon, ignoring reconnect\n");
515 cls.signon = 0; // need new connection messages
520 =====================
523 User command to connect to server
524 =====================
526 void Host_Connect_f (void)
530 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
533 // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
534 if(!rcon_secure.integer)
535 Cvar_SetQuick(&rcon_password, "");
536 CL_EstablishConnection(Cmd_Argv(1));
541 ===============================================================================
545 ===============================================================================
548 #define SAVEGAME_VERSION 5
550 void Host_Savegame_to (const char *name)
553 int i, lightstyles = 64;
554 char comment[SAVEGAME_COMMENT_LENGTH+1];
557 // first we have to figure out if this can be saved in 64 lightstyles
558 // (for Quake compatibility)
559 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
560 if (sv.lightstyles[i][0])
563 isserver = !strcmp(PRVM_NAME, "server");
565 Con_Printf("Saving game to %s...\n", name);
566 f = FS_OpenRealFile(name, "wb", false);
569 Con_Print("ERROR: couldn't open.\n");
573 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
575 memset(comment, 0, sizeof(comment));
577 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);
579 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
580 // convert space to _ to make stdio happy
581 // LordHavoc: convert control characters to _ as well
582 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
583 if (ISWHITESPACEORCONTROL(comment[i]))
585 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
587 FS_Printf(f, "%s\n", comment);
590 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
591 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
592 FS_Printf(f, "%d\n", current_skill);
593 FS_Printf(f, "%s\n", sv.name);
594 FS_Printf(f, "%f\n",sv.time);
598 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
599 FS_Printf(f, "(dummy)\n");
600 FS_Printf(f, "%d\n", 0);
601 FS_Printf(f, "%s\n", "(dummy)");
602 FS_Printf(f, "%f\n", realtime);
605 // write the light styles
606 for (i=0 ; i<lightstyles ; i++)
608 if (isserver && sv.lightstyles[i][0])
609 FS_Printf(f, "%s\n", sv.lightstyles[i]);
614 PRVM_ED_WriteGlobals (f);
615 for (i=0 ; i<prog->num_edicts ; i++)
617 FS_Printf(f,"// edict %d\n", i);
618 //Con_Printf("edict %d...\n", i);
619 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
624 FS_Printf(f,"// DarkPlaces extended savegame\n");
625 // darkplaces extension - extra lightstyles, support for color lightstyles
626 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
627 if (isserver && sv.lightstyles[i][0])
628 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
630 // darkplaces extension - model precaches
631 for (i=1 ; i<MAX_MODELS ; i++)
632 if (sv.model_precache[i][0])
633 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
635 // darkplaces extension - sound precaches
636 for (i=1 ; i<MAX_SOUNDS ; i++)
637 if (sv.sound_precache[i][0])
638 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
643 Con_Print("done.\n");
651 void Host_Savegame_f (void)
653 char name[MAX_QPATH];
657 Con_Print("Can't save - no server running.\n");
663 // singleplayer checks
666 Con_Print("Can't save in intermission.\n");
670 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
672 Con_Print("Can't savegame with a dead player\n");
677 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");
681 Con_Print("save <savename> : save a game\n");
685 if (strstr(Cmd_Argv(1), ".."))
687 Con_Print("Relative pathnames are not allowed.\n");
691 strlcpy (name, Cmd_Argv(1), sizeof (name));
692 FS_DefaultExtension (name, ".sav", sizeof (name));
695 Host_Savegame_to(name);
705 void Host_Loadgame_f (void)
707 char filename[MAX_QPATH];
708 char mapname[MAX_QPATH];
718 float spawn_parms[NUM_SPAWN_PARMS];
722 Con_Print("load <savename> : load a game\n");
726 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
727 FS_DefaultExtension (filename, ".sav", sizeof (filename));
729 Con_Printf("Loading game from %s...\n", filename);
731 // stop playing demos
732 if (cls.demoplayback)
738 cls.demonum = -1; // stop demo loop in case this fails
740 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
743 Con_Print("ERROR: couldn't open.\n");
747 if(developer_entityparsing.integer)
748 Con_Printf("Host_Loadgame_f: loading version\n");
751 COM_ParseToken_Simple(&t, false, false);
752 version = atoi(com_token);
753 if (version != SAVEGAME_VERSION)
756 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
760 if(developer_entityparsing.integer)
761 Con_Printf("Host_Loadgame_f: loading description\n");
764 COM_ParseToken_Simple(&t, false, false);
766 for (i = 0;i < NUM_SPAWN_PARMS;i++)
768 COM_ParseToken_Simple(&t, false, false);
769 spawn_parms[i] = atof(com_token);
772 COM_ParseToken_Simple(&t, false, false);
773 // this silliness is so we can load 1.06 save files, which have float skill values
774 current_skill = (int)(atof(com_token) + 0.5);
775 Cvar_SetValue ("skill", (float)current_skill);
777 if(developer_entityparsing.integer)
778 Con_Printf("Host_Loadgame_f: loading mapname\n");
781 COM_ParseToken_Simple(&t, false, false);
782 strlcpy (mapname, com_token, sizeof(mapname));
784 if(developer_entityparsing.integer)
785 Con_Printf("Host_Loadgame_f: loading time\n");
788 COM_ParseToken_Simple(&t, false, false);
789 time = atof(com_token);
791 allowcheats = sv_cheats.integer != 0;
793 if(developer_entityparsing.integer)
794 Con_Printf("Host_Loadgame_f: spawning server\n");
796 SV_SpawnServer (mapname);
800 Con_Print("Couldn't load map\n");
803 sv.paused = true; // pause until all clients connect
806 if(developer_entityparsing.integer)
807 Con_Printf("Host_Loadgame_f: loading light styles\n");
809 // load the light styles
815 for (i = 0;i < MAX_LIGHTSTYLES;i++)
819 COM_ParseToken_Simple(&t, false, false);
820 // if this is a 64 lightstyle savegame produced by Quake, stop now
821 // we have to check this because darkplaces may save more than 64
822 if (com_token[0] == '{')
827 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
830 if(developer_entityparsing.integer)
831 Con_Printf("Host_Loadgame_f: skipping until globals\n");
833 // now skip everything before the first opening brace
834 // (this is for forward compatibility, so that older versions (at
835 // least ones with this fix) can load savegames with extra data before the
836 // first brace, as might be produced by a later engine version)
840 if (!COM_ParseToken_Simple(&t, false, false))
842 if (com_token[0] == '{')
849 // load the edicts out of the savegame file
854 while (COM_ParseToken_Simple(&t, false, false))
855 if (!strcmp(com_token, "}"))
857 if (!COM_ParseToken_Simple(&start, false, false))
862 if (strcmp(com_token,"{"))
865 Host_Error ("First token isn't a brace");
870 if(developer_entityparsing.integer)
871 Con_Printf("Host_Loadgame_f: loading globals\n");
873 // parse the global vars
874 PRVM_ED_ParseGlobals (start);
879 if (entnum >= MAX_EDICTS)
882 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
884 while (entnum >= prog->max_edicts)
885 PRVM_MEM_IncreaseEdicts();
886 ent = PRVM_EDICT_NUM(entnum);
887 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
888 ent->priv.server->free = false;
890 if(developer_entityparsing.integer)
891 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
893 PRVM_ED_ParseEdict (start, ent);
895 // link it into the bsp tree
896 if (!ent->priv.server->free)
897 SV_LinkEdict (ent, false);
904 prog->num_edicts = entnum;
907 for (i = 0;i < NUM_SPAWN_PARMS;i++)
908 svs.clients[0].spawn_parms[i] = spawn_parms[i];
910 if(developer_entityparsing.integer)
911 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
913 // read extended data if present
914 // the extended data is stored inside a /* */ comment block, which the
915 // parser intentionally skips, so we have to check for it manually here
918 while (*end == '\r' || *end == '\n')
920 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
922 if(developer_entityparsing.integer)
923 Con_Printf("Host_Loadgame_f: loading extended data\n");
925 Con_Printf("Loading extended DarkPlaces savegame\n");
927 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
928 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
929 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
930 while (COM_ParseToken_Simple(&t, false, false))
932 if (!strcmp(com_token, "sv.lightstyles"))
934 COM_ParseToken_Simple(&t, false, false);
936 COM_ParseToken_Simple(&t, false, false);
937 if (i >= 0 && i < MAX_LIGHTSTYLES)
938 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
940 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
942 else if (!strcmp(com_token, "sv.model_precache"))
944 COM_ParseToken_Simple(&t, false, false);
946 COM_ParseToken_Simple(&t, false, false);
947 if (i >= 0 && i < MAX_MODELS)
949 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
950 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL);
953 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
955 else if (!strcmp(com_token, "sv.sound_precache"))
957 COM_ParseToken_Simple(&t, false, false);
959 COM_ParseToken_Simple(&t, false, false);
960 if (i >= 0 && i < MAX_SOUNDS)
961 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
963 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
965 // skip any trailing text or unrecognized commands
966 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
973 if(developer_entityparsing.integer)
974 Con_Printf("Host_Loadgame_f: finished\n");
978 // make sure we're connected to loopback
979 if (sv.active && cls.state == ca_disconnected)
980 CL_EstablishConnection("local:1");
983 //============================================================================
986 ======================
988 ======================
990 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
991 void Host_Name_f (void)
994 qboolean valid_colors;
995 char newName[sizeof(host_client->name)];
997 if (Cmd_Argc () == 1)
999 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
1003 if (Cmd_Argc () == 2)
1004 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
1006 strlcpy (newName, Cmd_Args(), sizeof (newName));
1008 if (cmd_source == src_command)
1010 Cvar_Set ("_cl_name", newName);
1014 if (realtime < host_client->nametime)
1016 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1020 host_client->nametime = realtime + 5;
1022 // point the string back at updateclient->name to keep it safe
1023 strlcpy (host_client->name, newName, sizeof (host_client->name));
1025 for (i = 0, j = 0;host_client->name[i];i++)
1026 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1027 host_client->name[j++] = host_client->name[i];
1028 host_client->name[j] = 0;
1030 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1031 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1033 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1034 host_client->name[sizeof(host_client->name) - 1] = 0;
1035 host_client->name[0] = STRING_COLOR_TAG;
1036 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1039 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1040 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1043 l = strlen(host_client->name);
1044 if(l < sizeof(host_client->name) - 1)
1046 // duplicate the color tag to escape it
1047 host_client->name[i] = STRING_COLOR_TAG;
1048 host_client->name[i+1] = 0;
1049 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1053 // remove the last character to fix the color code
1054 host_client->name[l-1] = 0;
1055 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1059 // find the last color tag offset and decide if we need to add a reset tag
1060 for (i = 0, j = -1;host_client->name[i];i++)
1062 if (host_client->name[i] == STRING_COLOR_TAG)
1064 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1067 // if this happens to be a reset tag then we don't need one
1068 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1073 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]))
1079 if (host_client->name[i+1] == STRING_COLOR_TAG)
1086 // does not end in the default color string, so add it
1087 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1088 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1090 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1091 if (strcmp(host_client->old_name, host_client->name))
1093 if (host_client->spawned)
1094 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1095 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1096 // send notification to all clients
1097 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1098 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1099 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1100 SV_WriteNetnameIntoDemo(host_client);
1105 ======================
1107 ======================
1109 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1110 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1111 void Host_Playermodel_f (void)
1114 char newPath[sizeof(host_client->playermodel)];
1116 if (Cmd_Argc () == 1)
1118 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1122 if (Cmd_Argc () == 2)
1123 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1125 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1127 for (i = 0, j = 0;newPath[i];i++)
1128 if (newPath[i] != '\r' && newPath[i] != '\n')
1129 newPath[j++] = newPath[i];
1132 if (cmd_source == src_command)
1134 Cvar_Set ("_cl_playermodel", newPath);
1139 if (realtime < host_client->nametime)
1141 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1145 host_client->nametime = realtime + 5;
1148 // point the string back at updateclient->name to keep it safe
1149 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1150 if( prog->fieldoffsets.playermodel >= 0 )
1151 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1152 if (strcmp(host_client->old_model, host_client->playermodel))
1154 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1155 /*// send notification to all clients
1156 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1157 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1158 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1163 ======================
1165 ======================
1167 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1168 void Host_Playerskin_f (void)
1171 char newPath[sizeof(host_client->playerskin)];
1173 if (Cmd_Argc () == 1)
1175 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1179 if (Cmd_Argc () == 2)
1180 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1182 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1184 for (i = 0, j = 0;newPath[i];i++)
1185 if (newPath[i] != '\r' && newPath[i] != '\n')
1186 newPath[j++] = newPath[i];
1189 if (cmd_source == src_command)
1191 Cvar_Set ("_cl_playerskin", newPath);
1196 if (realtime < host_client->nametime)
1198 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1202 host_client->nametime = realtime + 5;
1205 // point the string back at updateclient->name to keep it safe
1206 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1207 if( prog->fieldoffsets.playerskin >= 0 )
1208 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1209 if (strcmp(host_client->old_skin, host_client->playerskin))
1211 //if (host_client->spawned)
1212 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1213 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1214 /*// send notification to all clients
1215 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1216 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1217 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1221 void Host_Version_f (void)
1223 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1226 void Host_Say(qboolean teamonly)
1232 // LordHavoc: long say messages
1234 qboolean fromServer = false;
1236 if (cmd_source == src_command)
1238 if (cls.state == ca_dedicated)
1245 Cmd_ForwardToServer ();
1250 if (Cmd_Argc () < 2)
1253 if (!teamplay.integer)
1263 // note this uses the chat prefix \001
1264 if (!fromServer && !teamonly)
1265 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1266 else if (!fromServer && teamonly)
1267 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1268 else if(*(sv_adminnick.string))
1269 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1271 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1272 p2 = text + strlen(text);
1273 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1275 if (p2[-1] == '\"' && quoted)
1280 strlcat(text, "\n", sizeof(text));
1282 // note: save is not a valid edict if fromServer is true
1284 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1285 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1286 SV_ClientPrint(text);
1289 if (cls.state == ca_dedicated)
1290 Con_Print(&text[1]);
1294 void Host_Say_f(void)
1300 void Host_Say_Team_f(void)
1306 void Host_Tell_f(void)
1308 const char *playername_start = NULL;
1309 size_t playername_length = 0;
1310 int playernumber = 0;
1313 const char *p1, *p2;
1314 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1315 qboolean fromServer = false;
1317 if (cmd_source == src_command)
1319 if (cls.state == ca_dedicated)
1323 Cmd_ForwardToServer ();
1328 if (Cmd_Argc () < 2)
1331 // note this uses the chat prefix \001
1333 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1334 else if(*(sv_adminnick.string))
1335 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1337 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1340 p2 = p1 + strlen(p1);
1341 // remove the target name
1342 while (p1 < p2 && *p1 == ' ')
1347 while (p1 < p2 && *p1 == ' ')
1349 while (p1 < p2 && isdigit(*p1))
1351 playernumber = playernumber * 10 + (*p1 - '0');
1359 playername_start = p1;
1360 while (p1 < p2 && *p1 != '"')
1362 playername_length = p1 - playername_start;
1368 playername_start = p1;
1369 while (p1 < p2 && *p1 != ' ')
1371 playername_length = p1 - playername_start;
1373 while (p1 < p2 && *p1 == ' ')
1375 if(playername_start)
1377 // set playernumber to the right client
1379 if(playername_length >= sizeof(namebuf))
1382 Con_Print("Host_Tell: too long player name/ID\n");
1384 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1387 memcpy(namebuf, playername_start, playername_length);
1388 namebuf[playername_length] = 0;
1389 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1391 if (!svs.clients[playernumber].active)
1393 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1397 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1400 Con_Print("Host_Tell: invalid player name/ID\n");
1402 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1405 // remove trailing newlines
1406 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1408 // remove quotes if present
1414 else if (fromServer)
1415 Con_Print("Host_Tell: missing end quote\n");
1417 SV_ClientPrint("Host_Tell: missing end quote\n");
1419 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1422 return; // empty say
1423 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1429 host_client = svs.clients + playernumber;
1430 SV_ClientPrint(text);
1440 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1441 void Host_Color(int changetop, int changebottom)
1443 int top, bottom, playercolor;
1445 // get top and bottom either from the provided values or the current values
1446 // (allows changing only top or bottom, or both at once)
1447 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1448 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1452 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1458 playercolor = top*16 + bottom;
1460 if (cmd_source == src_command)
1462 Cvar_SetValueQuick(&cl_color, playercolor);
1466 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1469 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1471 Con_DPrint("Calling SV_ChangeTeam\n");
1472 prog->globals.server->time = sv.time;
1473 prog->globals.generic[OFS_PARM0] = playercolor;
1474 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1475 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1480 if (host_client->edict)
1482 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1483 val->_float = playercolor;
1484 host_client->edict->fields.server->team = bottom + 1;
1486 host_client->colors = playercolor;
1487 if (host_client->old_colors != host_client->colors)
1489 host_client->old_colors = host_client->colors;
1490 // send notification to all clients
1491 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1492 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1493 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1498 void Host_Color_f(void)
1502 if (Cmd_Argc() == 1)
1504 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1505 Con_Print("color <0-15> [0-15]\n");
1509 if (Cmd_Argc() == 2)
1510 top = bottom = atoi(Cmd_Argv(1));
1513 top = atoi(Cmd_Argv(1));
1514 bottom = atoi(Cmd_Argv(2));
1516 Host_Color(top, bottom);
1519 void Host_TopColor_f(void)
1521 if (Cmd_Argc() == 1)
1523 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1524 Con_Print("topcolor <0-15>\n");
1528 Host_Color(atoi(Cmd_Argv(1)), -1);
1531 void Host_BottomColor_f(void)
1533 if (Cmd_Argc() == 1)
1535 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1536 Con_Print("bottomcolor <0-15>\n");
1540 Host_Color(-1, atoi(Cmd_Argv(1)));
1543 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1544 void Host_Rate_f(void)
1548 if (Cmd_Argc() != 2)
1550 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1551 Con_Print("rate <bytespersecond>\n");
1555 rate = atoi(Cmd_Argv(1));
1557 if (cmd_source == src_command)
1559 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1563 host_client->rate = rate;
1571 void Host_Kill_f (void)
1573 if (host_client->edict->fields.server->health <= 0)
1575 SV_ClientPrint("Can't suicide -- already dead!\n");
1579 prog->globals.server->time = sv.time;
1580 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1581 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1590 void Host_Pause_f (void)
1592 if (!pausable.integer)
1593 SV_ClientPrint("Pause not allowed.\n");
1597 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1598 // send notification to all clients
1599 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1600 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1605 ======================
1607 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1608 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1609 ======================
1611 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)"};
1612 static void Host_PModel_f (void)
1617 if (Cmd_Argc () == 1)
1619 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1622 i = atoi(Cmd_Argv(1));
1624 if (cmd_source == src_command)
1626 if (cl_pmodel.integer == i)
1628 Cvar_SetValue ("_cl_pmodel", i);
1629 if (cls.state == ca_connected)
1630 Cmd_ForwardToServer ();
1634 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1638 //===========================================================================
1646 void Host_PreSpawn_f (void)
1648 if (host_client->spawned)
1650 Con_Print("prespawn not valid -- already spawned\n");
1654 if (host_client->netconnection)
1656 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1657 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1658 MSG_WriteByte (&host_client->netconnection->message, 2);
1659 host_client->sendsignon = 0; // enable unlimited sends again
1662 // reset the name change timer because the client will send name soon
1663 host_client->nametime = 0;
1671 void Host_Spawn_f (void)
1675 int stats[MAX_CL_STATS];
1677 if (host_client->spawned)
1679 Con_Print("Spawn not valid -- already spawned\n");
1683 // reset name change timer again because they might want to change name
1684 // again in the first 5 seconds after connecting
1685 host_client->nametime = 0;
1687 // LordHavoc: moved this above the QC calls at FrikaC's request
1688 // LordHavoc: commented this out
1689 //if (host_client->netconnection)
1690 // SZ_Clear (&host_client->netconnection->message);
1692 // run the entrance script
1695 // loaded games are fully initialized already
1696 if (prog->funcoffsets.RestoreGame)
1698 Con_DPrint("Calling RestoreGame\n");
1699 prog->globals.server->time = sv.time;
1700 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1701 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1706 //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);
1708 // copy spawn parms out of the client_t
1709 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1710 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1712 // call the spawn function
1713 host_client->clientconnectcalled = true;
1714 prog->globals.server->time = sv.time;
1715 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1716 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1718 if (cls.state == ca_dedicated)
1719 Con_Printf("%s connected\n", host_client->name);
1721 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1724 if (!host_client->netconnection)
1727 // send time of update
1728 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1729 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1731 // send all current names, colors, and frag counts
1732 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1734 if (!client->active)
1736 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1737 MSG_WriteByte (&host_client->netconnection->message, i);
1738 MSG_WriteString (&host_client->netconnection->message, client->name);
1739 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1740 MSG_WriteByte (&host_client->netconnection->message, i);
1741 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1742 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1743 MSG_WriteByte (&host_client->netconnection->message, i);
1744 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1747 // send all current light styles
1748 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1750 if (sv.lightstyles[i][0])
1752 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1753 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1754 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1759 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1760 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1761 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1763 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1764 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1765 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1767 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1768 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1769 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1771 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1772 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1773 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1776 // Never send a roll angle, because savegames can catch the server
1777 // in a state where it is expecting the client to correct the angle
1778 // and it won't happen if the game was just loaded, so you wind up
1779 // with a permanent head tilt
1782 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1783 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1784 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1785 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1789 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1790 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1791 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1792 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1795 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1797 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1798 MSG_WriteByte (&host_client->netconnection->message, 3);
1806 void Host_Begin_f (void)
1808 host_client->spawned = true;
1810 // LordHavoc: note: this code also exists in SV_DropClient
1814 for (i = 0;i < svs.maxclients;i++)
1815 if (svs.clients[i].active && !svs.clients[i].spawned)
1817 if (i == svs.maxclients)
1819 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1820 sv.paused = sv.loadgame = false; // we're basically done with loading now
1825 //===========================================================================
1832 Kicks a user off of the server
1835 void Host_Kick_f (void)
1838 const char *message = NULL;
1841 qboolean byNumber = false;
1849 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1851 i = (int)(atof(Cmd_Argv(2)) - 1);
1852 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1858 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1860 if (!host_client->active)
1862 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1867 if (i < svs.maxclients)
1869 if (cmd_source == src_command)
1871 if (cls.state == ca_dedicated)
1874 who = cl_name.string;
1879 // can't kick yourself!
1880 if (host_client == save)
1885 message = Cmd_Args();
1886 COM_ParseToken_Simple(&message, false, false);
1889 message++; // skip the #
1890 while (*message == ' ') // skip white space
1892 message += strlen(Cmd_Argv(2)); // skip the number
1894 while (*message && *message == ' ')
1898 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1900 SV_ClientPrintf("Kicked by %s\n", who);
1901 SV_DropClient (false); // kicked
1909 ===============================================================================
1913 ===============================================================================
1921 void Host_Give_f (void)
1929 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1934 v = atoi (Cmd_Argv(2));
1948 // MED 01/04/97 added hipnotic give stuff
1949 if (gamemode == GAME_HIPNOTIC)
1954 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1956 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1958 else if (t[0] == '9')
1959 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1960 else if (t[0] == '0')
1961 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1962 else if (t[0] >= '2')
1963 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1968 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1973 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1976 host_client->edict->fields.server->ammo_shells = v;
1979 if (gamemode == GAME_ROGUE)
1981 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1984 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1985 host_client->edict->fields.server->ammo_nails = v;
1990 host_client->edict->fields.server->ammo_nails = v;
1994 if (gamemode == GAME_ROGUE)
1996 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
2000 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2001 host_client->edict->fields.server->ammo_nails = v;
2006 if (gamemode == GAME_ROGUE)
2008 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
2012 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2013 host_client->edict->fields.server->ammo_rockets = v;
2018 host_client->edict->fields.server->ammo_rockets = v;
2022 if (gamemode == GAME_ROGUE)
2024 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2028 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2029 host_client->edict->fields.server->ammo_rockets = v;
2034 host_client->edict->fields.server->health = v;
2037 if (gamemode == GAME_ROGUE)
2039 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2043 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2044 host_client->edict->fields.server->ammo_cells = v;
2049 host_client->edict->fields.server->ammo_cells = v;
2053 if (gamemode == GAME_ROGUE)
2055 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2059 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2060 host_client->edict->fields.server->ammo_cells = v;
2067 prvm_edict_t *FindViewthing (void)
2072 for (i=0 ; i<prog->num_edicts ; i++)
2074 e = PRVM_EDICT_NUM(i);
2075 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2078 Con_Print("No viewthing on map\n");
2087 void Host_Viewmodel_f (void)
2096 e = FindViewthing ();
2101 m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
2102 if (!m || !m->loaded || !m->Draw)
2104 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2108 e->fields.server->frame = 0;
2109 cl.model_precache[(int)e->fields.server->modelindex] = m;
2117 void Host_Viewframe_f (void)
2127 e = FindViewthing ();
2131 m = cl.model_precache[(int)e->fields.server->modelindex];
2133 f = atoi(Cmd_Argv(1));
2134 if (f >= m->numframes)
2137 e->fields.server->frame = f;
2141 void PrintFrameName (dp_model_t *m, int frame)
2144 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2146 Con_Printf("frame %i\n", frame);
2154 void Host_Viewnext_f (void)
2163 e = FindViewthing ();
2167 m = cl.model_precache[(int)e->fields.server->modelindex];
2169 e->fields.server->frame = e->fields.server->frame + 1;
2170 if (e->fields.server->frame >= m->numframes)
2171 e->fields.server->frame = m->numframes - 1;
2173 PrintFrameName (m, (int)e->fields.server->frame);
2181 void Host_Viewprev_f (void)
2190 e = FindViewthing ();
2195 m = cl.model_precache[(int)e->fields.server->modelindex];
2197 e->fields.server->frame = e->fields.server->frame - 1;
2198 if (e->fields.server->frame < 0)
2199 e->fields.server->frame = 0;
2201 PrintFrameName (m, (int)e->fields.server->frame);
2205 ===============================================================================
2209 ===============================================================================
2218 void Host_Startdemos_f (void)
2222 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2228 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2231 Con_DPrintf("%i demo(s) in loop\n", c);
2233 for (i=1 ; i<c+1 ; i++)
2234 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2236 // LordHavoc: clear the remaining slots
2237 for (;i <= MAX_DEMOS;i++)
2238 cls.demos[i-1][0] = 0;
2240 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2254 Return to looping demos
2257 void Host_Demos_f (void)
2259 if (cls.state == ca_dedicated)
2261 if (cls.demonum == -1)
2271 Return to looping demos
2274 void Host_Stopdemo_f (void)
2276 if (!cls.demoplayback)
2279 Host_ShutdownServer ();
2282 void Host_SendCvar_f (void)
2286 const char *cvarname;
2291 cvarname = Cmd_Argv(1);
2292 if (cls.state == ca_connected)
2294 c = Cvar_FindVar(cvarname);
2295 // LordHavoc: if there is no such cvar or if it is private, send a
2296 // reply indicating that it has no value
2297 if(!c || (c->flags & CVAR_PRIVATE))
2298 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2300 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2303 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2307 if (cls.state != ca_dedicated)
2311 for(;i<svs.maxclients;i++)
2312 if(svs.clients[i].active && svs.clients[i].netconnection)
2314 host_client = &svs.clients[i];
2315 Host_ClientCommands("sendcvar %s\n", cvarname);
2320 static void MaxPlayers_f(void)
2324 if (Cmd_Argc() != 2)
2326 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
2332 Con_Print("maxplayers can not be changed while a server is running.\n");
2333 Con_Print("It will be changed on next server startup (\"map\" command).\n");
2336 n = atoi(Cmd_Argv(1));
2337 n = bound(1, n, MAX_SCOREBOARD);
2338 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2340 svs.maxclients_next = n;
2342 Cvar_Set ("deathmatch", "0");
2344 Cvar_Set ("deathmatch", "1");
2347 //=============================================================================
2349 // QuakeWorld commands
2352 =====================
2355 Send the rest of the command line over as
2356 an unconnected command.
2357 =====================
2359 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2363 lhnetsocket_t *mysocket;
2365 if (!rcon_password.string || !rcon_password.string[0])
2367 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2371 for (i = 0;rcon_password.string[i];i++)
2373 if (ISWHITESPACE(rcon_password.string[i]))
2375 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2381 to = cls.netcon->peeraddress;
2384 if (!rcon_address.string[0])
2386 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2389 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2391 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2394 // simply put together the rcon packet and send it
2395 if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer)
2399 dpsnprintf(argbuf, sizeof(argbuf), "%ld %s", (long) time(NULL), Cmd_Args());
2400 memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24);
2401 if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, strlen(rcon_password.string)))
2404 strlcpy(buf + 41, argbuf, sizeof(buf) - 41);
2405 NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to);
2410 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2416 ====================
2419 user <name or userid>
2421 Dump userdata / masterdata for a user
2422 ====================
2424 void Host_User_f (void) // credit: taken from QuakeWorld
2429 if (Cmd_Argc() != 2)
2431 Con_Printf ("Usage: user <username / userid>\n");
2435 uid = atoi(Cmd_Argv(1));
2437 for (i = 0;i < cl.maxclients;i++)
2439 if (!cl.scores[i].name[0])
2441 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2443 InfoString_Print(cl.scores[i].qw_userinfo);
2447 Con_Printf ("User not in server.\n");
2451 ====================
2454 Dump userids for all current players
2455 ====================
2457 void Host_Users_f (void) // credit: taken from QuakeWorld
2463 Con_Printf ("userid frags name\n");
2464 Con_Printf ("------ ----- ----\n");
2465 for (i = 0;i < cl.maxclients;i++)
2467 if (cl.scores[i].name[0])
2469 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2474 Con_Printf ("%i total users\n", c);
2479 Host_FullServerinfo_f
2481 Sent by server when serverinfo changes
2484 // TODO: shouldn't this be a cvar instead?
2485 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2488 if (Cmd_Argc() != 2)
2490 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2494 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2495 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2496 cl.qw_teamplay = atoi(temp);
2503 Allow clients to change userinfo
2507 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2514 if (Cmd_Argc() != 2)
2516 Con_Printf ("fullinfo <complete info string>\n");
2526 while (*s && *s != '\\')
2532 Con_Printf ("MISSING VALUE\n");
2538 while (*s && *s != '\\')
2545 CL_SetInfo(key, value, false, false, false, false);
2553 Allow clients to change userinfo
2556 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2558 if (Cmd_Argc() == 1)
2560 InfoString_Print(cls.userinfo);
2563 if (Cmd_Argc() != 3)
2565 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2568 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2572 ====================
2575 packet <destination> <contents>
2577 Contents allows \n escape character
2578 ====================
2580 void Host_Packet_f (void) // credit: taken from QuakeWorld
2586 lhnetaddress_t address;
2587 lhnetsocket_t *mysocket;
2589 if (Cmd_Argc() != 3)
2591 Con_Printf ("packet <destination> <contents>\n");
2595 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2597 Con_Printf ("Bad address\n");
2603 send[0] = send[1] = send[2] = send[3] = 0xff;
2605 l = (int)strlen (in);
2606 for (i=0 ; i<l ; i++)
2608 if (out >= send + sizeof(send) - 1)
2610 if (in[i] == '\\' && in[i+1] == 'n')
2615 else if (in[i] == '\\' && in[i+1] == '0')
2620 else if (in[i] == '\\' && in[i+1] == 't')
2625 else if (in[i] == '\\' && in[i+1] == 'r')
2630 else if (in[i] == '\\' && in[i+1] == '"')
2639 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2641 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2643 NetConn_Write(mysocket, send, out - send, &address);
2647 ====================
2650 Send back ping and packet loss update for all current players to this player
2651 ====================
2653 void Host_Pings_f (void)
2655 int i, j, ping, packetloss;
2658 if (!host_client->netconnection)
2661 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2663 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2664 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2666 for (i = 0;i < svs.maxclients;i++)
2669 if (svs.clients[i].netconnection)
2670 for (j = 0;j < NETGRAPH_PACKETS;j++)
2671 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2673 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2674 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2675 ping = bound(0, ping, 9999);
2676 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2678 // send qw_svc_updateping and qw_svc_updatepl messages
2679 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2680 MSG_WriteShort(&host_client->netconnection->message, ping);
2681 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2682 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2686 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2687 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2688 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2691 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2692 MSG_WriteString(&host_client->netconnection->message, "\n");
2695 void Host_PingPLReport_f(void)
2699 if (l > cl.maxclients)
2701 for (i = 0;i < l;i++)
2703 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2704 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2708 //=============================================================================
2715 void Host_InitCommands (void)
2717 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2719 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2720 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2721 if (gamemode == GAME_NEHAHRA)
2723 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2724 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2725 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2726 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2727 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2731 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2732 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2733 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2734 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2735 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2737 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2738 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2739 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2740 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2741 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)");
2742 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2743 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2744 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2745 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2746 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2747 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2748 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2749 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2750 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2751 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2753 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2754 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2755 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2757 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2758 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2759 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2760 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2762 Cvar_RegisterVariable (&cl_name);
2763 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2764 Cvar_RegisterVariable (&cl_color);
2765 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2766 Cvar_RegisterVariable (&cl_rate);
2767 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2768 if (gamemode == GAME_NEHAHRA)
2770 Cvar_RegisterVariable (&cl_pmodel);
2771 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2774 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2775 Cvar_RegisterVariable (&cl_playermodel);
2776 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2777 Cvar_RegisterVariable (&cl_playerskin);
2778 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2780 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2781 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2782 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)");
2783 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2785 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2787 Cvar_RegisterVariable (&rcon_password);
2788 Cvar_RegisterVariable (&rcon_address);
2789 Cvar_RegisterVariable (&rcon_secure);
2790 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)");
2791 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");
2792 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2793 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2794 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2795 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2796 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2797 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2798 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2799 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2801 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)");
2802 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)");
2804 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)");
2805 Cvar_RegisterVariable (&r_fixtrans_auto);
2807 Cvar_RegisterVariable (&team);
2808 Cvar_RegisterVariable (&skin);
2809 Cvar_RegisterVariable (&noaim);
2811 Cvar_RegisterVariable(&sv_cheats);
2812 Cvar_RegisterVariable(&sv_adminnick);
2813 Cvar_RegisterVariable(&sv_status_privacy);
2814 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2817 void Host_NoOperation_f(void)