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", "1", "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 Cvar_SetQuick(&rcon_password, "");
479 CL_EstablishConnection(temp);
482 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
485 // if connected, do something based on protocol
486 if (cls.protocol == PROTOCOL_QUAKEWORLD)
488 // quakeworld can just re-login
489 if (cls.qw_downloadmemory) // don't change when downloading
494 if (cls.state == ca_connected && cls.signon < SIGNONS)
496 Con_Printf("reconnecting...\n");
497 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
498 MSG_WriteString(&cls.netcon->message, "new");
503 // netquake uses reconnect on level changes (silly)
506 Con_Print("reconnect : wait for signon messages again\n");
511 Con_Print("reconnect: no signon, ignoring reconnect\n");
514 cls.signon = 0; // need new connection messages
519 =====================
522 User command to connect to server
523 =====================
525 void Host_Connect_f (void)
529 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
532 // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
533 Cvar_SetQuick(&rcon_password, "");
534 CL_EstablishConnection(Cmd_Argv(1));
539 ===============================================================================
543 ===============================================================================
546 #define SAVEGAME_VERSION 5
548 void Host_Savegame_to (const char *name)
551 int i, lightstyles = 64;
552 char comment[SAVEGAME_COMMENT_LENGTH+1];
555 // first we have to figure out if this can be saved in 64 lightstyles
556 // (for Quake compatibility)
557 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
558 if (sv.lightstyles[i][0])
561 isserver = !strcmp(PRVM_NAME, "server");
563 Con_Printf("Saving game to %s...\n", name);
564 f = FS_OpenRealFile(name, "wb", false);
567 Con_Print("ERROR: couldn't open.\n");
571 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
573 memset(comment, 0, sizeof(comment));
575 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);
577 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
578 // convert space to _ to make stdio happy
579 // LordHavoc: convert control characters to _ as well
580 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
581 if (ISWHITESPACEORCONTROL(comment[i]))
583 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
585 FS_Printf(f, "%s\n", comment);
588 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
589 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
590 FS_Printf(f, "%d\n", current_skill);
591 FS_Printf(f, "%s\n", sv.name);
592 FS_Printf(f, "%f\n",sv.time);
596 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
597 FS_Printf(f, "(dummy)\n");
598 FS_Printf(f, "%d\n", 0);
599 FS_Printf(f, "%s\n", "(dummy)");
600 FS_Printf(f, "%f\n", realtime);
603 // write the light styles
604 for (i=0 ; i<lightstyles ; i++)
606 if (isserver && sv.lightstyles[i][0])
607 FS_Printf(f, "%s\n", sv.lightstyles[i]);
612 PRVM_ED_WriteGlobals (f);
613 for (i=0 ; i<prog->num_edicts ; i++)
615 FS_Printf(f,"// edict %d\n", i);
616 //Con_Printf("edict %d...\n", i);
617 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
622 FS_Printf(f,"// DarkPlaces extended savegame\n");
623 // darkplaces extension - extra lightstyles, support for color lightstyles
624 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
625 if (isserver && sv.lightstyles[i][0])
626 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
628 // darkplaces extension - model precaches
629 for (i=1 ; i<MAX_MODELS ; i++)
630 if (sv.model_precache[i][0])
631 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
633 // darkplaces extension - sound precaches
634 for (i=1 ; i<MAX_SOUNDS ; i++)
635 if (sv.sound_precache[i][0])
636 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
641 Con_Print("done.\n");
649 void Host_Savegame_f (void)
651 char name[MAX_QPATH];
655 Con_Print("Can't save - no server running.\n");
661 // singleplayer checks
664 Con_Print("Can't save in intermission.\n");
668 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
670 Con_Print("Can't savegame with a dead player\n");
675 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");
679 Con_Print("save <savename> : save a game\n");
683 if (strstr(Cmd_Argv(1), ".."))
685 Con_Print("Relative pathnames are not allowed.\n");
689 strlcpy (name, Cmd_Argv(1), sizeof (name));
690 FS_DefaultExtension (name, ".sav", sizeof (name));
693 Host_Savegame_to(name);
703 void Host_Loadgame_f (void)
705 char filename[MAX_QPATH];
706 char mapname[MAX_QPATH];
716 float spawn_parms[NUM_SPAWN_PARMS];
720 Con_Print("load <savename> : load a game\n");
724 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
725 FS_DefaultExtension (filename, ".sav", sizeof (filename));
727 Con_Printf("Loading game from %s...\n", filename);
729 // stop playing demos
730 if (cls.demoplayback)
736 cls.demonum = -1; // stop demo loop in case this fails
738 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
741 Con_Print("ERROR: couldn't open.\n");
745 if(developer_entityparsing.integer)
746 Con_Printf("Host_Loadgame_f: loading version\n");
749 COM_ParseToken_Simple(&t, false, false);
750 version = atoi(com_token);
751 if (version != SAVEGAME_VERSION)
754 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
758 if(developer_entityparsing.integer)
759 Con_Printf("Host_Loadgame_f: loading description\n");
762 COM_ParseToken_Simple(&t, false, false);
764 for (i = 0;i < NUM_SPAWN_PARMS;i++)
766 COM_ParseToken_Simple(&t, false, false);
767 spawn_parms[i] = atof(com_token);
770 COM_ParseToken_Simple(&t, false, false);
771 // this silliness is so we can load 1.06 save files, which have float skill values
772 current_skill = (int)(atof(com_token) + 0.5);
773 Cvar_SetValue ("skill", (float)current_skill);
775 if(developer_entityparsing.integer)
776 Con_Printf("Host_Loadgame_f: loading mapname\n");
779 COM_ParseToken_Simple(&t, false, false);
780 strlcpy (mapname, com_token, sizeof(mapname));
782 if(developer_entityparsing.integer)
783 Con_Printf("Host_Loadgame_f: loading time\n");
786 COM_ParseToken_Simple(&t, false, false);
787 time = atof(com_token);
789 allowcheats = sv_cheats.integer != 0;
791 if(developer_entityparsing.integer)
792 Con_Printf("Host_Loadgame_f: spawning server\n");
794 SV_SpawnServer (mapname);
798 Con_Print("Couldn't load map\n");
801 sv.paused = true; // pause until all clients connect
804 if(developer_entityparsing.integer)
805 Con_Printf("Host_Loadgame_f: loading light styles\n");
807 // load the light styles
813 for (i = 0;i < MAX_LIGHTSTYLES;i++)
817 COM_ParseToken_Simple(&t, false, false);
818 // if this is a 64 lightstyle savegame produced by Quake, stop now
819 // we have to check this because darkplaces may save more than 64
820 if (com_token[0] == '{')
825 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
828 if(developer_entityparsing.integer)
829 Con_Printf("Host_Loadgame_f: skipping until globals\n");
831 // now skip everything before the first opening brace
832 // (this is for forward compatibility, so that older versions (at
833 // least ones with this fix) can load savegames with extra data before the
834 // first brace, as might be produced by a later engine version)
838 if (!COM_ParseToken_Simple(&t, false, false))
840 if (com_token[0] == '{')
847 // load the edicts out of the savegame file
852 while (COM_ParseToken_Simple(&t, false, false))
853 if (!strcmp(com_token, "}"))
855 if (!COM_ParseToken_Simple(&start, false, false))
860 if (strcmp(com_token,"{"))
863 Host_Error ("First token isn't a brace");
868 if(developer_entityparsing.integer)
869 Con_Printf("Host_Loadgame_f: loading globals\n");
871 // parse the global vars
872 PRVM_ED_ParseGlobals (start);
877 if (entnum >= MAX_EDICTS)
880 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
882 while (entnum >= prog->max_edicts)
883 PRVM_MEM_IncreaseEdicts();
884 ent = PRVM_EDICT_NUM(entnum);
885 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
886 ent->priv.server->free = false;
888 if(developer_entityparsing.integer)
889 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
891 PRVM_ED_ParseEdict (start, ent);
893 // link it into the bsp tree
894 if (!ent->priv.server->free)
895 SV_LinkEdict (ent, false);
902 prog->num_edicts = entnum;
905 for (i = 0;i < NUM_SPAWN_PARMS;i++)
906 svs.clients[0].spawn_parms[i] = spawn_parms[i];
908 if(developer_entityparsing.integer)
909 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
911 // read extended data if present
912 // the extended data is stored inside a /* */ comment block, which the
913 // parser intentionally skips, so we have to check for it manually here
916 while (*end == '\r' || *end == '\n')
918 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
920 if(developer_entityparsing.integer)
921 Con_Printf("Host_Loadgame_f: loading extended data\n");
923 Con_Printf("Loading extended DarkPlaces savegame\n");
925 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
926 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
927 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
928 while (COM_ParseToken_Simple(&t, false, false))
930 if (!strcmp(com_token, "sv.lightstyles"))
932 COM_ParseToken_Simple(&t, false, false);
934 COM_ParseToken_Simple(&t, false, false);
935 if (i >= 0 && i < MAX_LIGHTSTYLES)
936 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
938 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
940 else if (!strcmp(com_token, "sv.model_precache"))
942 COM_ParseToken_Simple(&t, false, false);
944 COM_ParseToken_Simple(&t, false, false);
945 if (i >= 0 && i < MAX_MODELS)
947 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
948 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL);
951 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
953 else if (!strcmp(com_token, "sv.sound_precache"))
955 COM_ParseToken_Simple(&t, false, false);
957 COM_ParseToken_Simple(&t, false, false);
958 if (i >= 0 && i < MAX_SOUNDS)
959 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
961 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
963 // skip any trailing text or unrecognized commands
964 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
971 if(developer_entityparsing.integer)
972 Con_Printf("Host_Loadgame_f: finished\n");
976 // make sure we're connected to loopback
977 if (sv.active && cls.state == ca_disconnected)
978 CL_EstablishConnection("local:1");
981 //============================================================================
984 ======================
986 ======================
988 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
989 void Host_Name_f (void)
992 qboolean valid_colors;
993 char newName[sizeof(host_client->name)];
995 if (Cmd_Argc () == 1)
997 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
1001 if (Cmd_Argc () == 2)
1002 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
1004 strlcpy (newName, Cmd_Args(), sizeof (newName));
1006 if (cmd_source == src_command)
1008 Cvar_Set ("_cl_name", newName);
1012 if (realtime < host_client->nametime)
1014 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1018 host_client->nametime = realtime + 5;
1020 // point the string back at updateclient->name to keep it safe
1021 strlcpy (host_client->name, newName, sizeof (host_client->name));
1023 for (i = 0, j = 0;host_client->name[i];i++)
1024 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1025 host_client->name[j++] = host_client->name[i];
1026 host_client->name[j] = 0;
1028 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1029 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1031 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1032 host_client->name[sizeof(host_client->name) - 1] = 0;
1033 host_client->name[0] = STRING_COLOR_TAG;
1034 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1037 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1038 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1041 l = strlen(host_client->name);
1042 if(l < sizeof(host_client->name) - 1)
1044 // duplicate the color tag to escape it
1045 host_client->name[i] = STRING_COLOR_TAG;
1046 host_client->name[i+1] = 0;
1047 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1051 // remove the last character to fix the color code
1052 host_client->name[l-1] = 0;
1053 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1057 // find the last color tag offset and decide if we need to add a reset tag
1058 for (i = 0, j = -1;host_client->name[i];i++)
1060 if (host_client->name[i] == STRING_COLOR_TAG)
1062 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1065 // if this happens to be a reset tag then we don't need one
1066 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1071 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]))
1077 if (host_client->name[i+1] == STRING_COLOR_TAG)
1084 // does not end in the default color string, so add it
1085 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1086 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1088 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1089 if (strcmp(host_client->old_name, host_client->name))
1091 if (host_client->spawned)
1092 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1093 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1094 // send notification to all clients
1095 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1096 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1097 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1098 SV_WriteNetnameIntoDemo(host_client);
1103 ======================
1105 ======================
1107 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1108 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1109 void Host_Playermodel_f (void)
1112 char newPath[sizeof(host_client->playermodel)];
1114 if (Cmd_Argc () == 1)
1116 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1120 if (Cmd_Argc () == 2)
1121 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1123 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1125 for (i = 0, j = 0;newPath[i];i++)
1126 if (newPath[i] != '\r' && newPath[i] != '\n')
1127 newPath[j++] = newPath[i];
1130 if (cmd_source == src_command)
1132 Cvar_Set ("_cl_playermodel", newPath);
1137 if (realtime < host_client->nametime)
1139 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1143 host_client->nametime = realtime + 5;
1146 // point the string back at updateclient->name to keep it safe
1147 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1148 if( prog->fieldoffsets.playermodel >= 0 )
1149 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1150 if (strcmp(host_client->old_model, host_client->playermodel))
1152 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1153 /*// send notification to all clients
1154 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1155 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1156 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1161 ======================
1163 ======================
1165 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1166 void Host_Playerskin_f (void)
1169 char newPath[sizeof(host_client->playerskin)];
1171 if (Cmd_Argc () == 1)
1173 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1177 if (Cmd_Argc () == 2)
1178 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1180 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1182 for (i = 0, j = 0;newPath[i];i++)
1183 if (newPath[i] != '\r' && newPath[i] != '\n')
1184 newPath[j++] = newPath[i];
1187 if (cmd_source == src_command)
1189 Cvar_Set ("_cl_playerskin", newPath);
1194 if (realtime < host_client->nametime)
1196 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1200 host_client->nametime = realtime + 5;
1203 // point the string back at updateclient->name to keep it safe
1204 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1205 if( prog->fieldoffsets.playerskin >= 0 )
1206 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1207 if (strcmp(host_client->old_skin, host_client->playerskin))
1209 //if (host_client->spawned)
1210 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1211 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1212 /*// send notification to all clients
1213 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1214 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1215 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1219 void Host_Version_f (void)
1221 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1224 void Host_Say(qboolean teamonly)
1230 // LordHavoc: long say messages
1232 qboolean fromServer = false;
1234 if (cmd_source == src_command)
1236 if (cls.state == ca_dedicated)
1243 Cmd_ForwardToServer ();
1248 if (Cmd_Argc () < 2)
1251 if (!teamplay.integer)
1261 // note this uses the chat prefix \001
1262 if (!fromServer && !teamonly)
1263 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1264 else if (!fromServer && teamonly)
1265 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1266 else if(*(sv_adminnick.string))
1267 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1269 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1270 p2 = text + strlen(text);
1271 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1273 if (p2[-1] == '\"' && quoted)
1278 strlcat(text, "\n", sizeof(text));
1280 // note: save is not a valid edict if fromServer is true
1282 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1283 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1284 SV_ClientPrint(text);
1287 if (cls.state == ca_dedicated)
1288 Con_Print(&text[1]);
1292 void Host_Say_f(void)
1298 void Host_Say_Team_f(void)
1304 void Host_Tell_f(void)
1306 const char *playername_start = NULL;
1307 size_t playername_length = 0;
1308 int playernumber = 0;
1311 const char *p1, *p2;
1312 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1313 qboolean fromServer = false;
1315 if (cmd_source == src_command)
1317 if (cls.state == ca_dedicated)
1321 Cmd_ForwardToServer ();
1326 if (Cmd_Argc () < 2)
1329 // note this uses the chat prefix \001
1331 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1332 else if(*(sv_adminnick.string))
1333 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1335 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1338 p2 = p1 + strlen(p1);
1339 // remove the target name
1340 while (p1 < p2 && *p1 == ' ')
1345 while (p1 < p2 && *p1 == ' ')
1347 while (p1 < p2 && isdigit(*p1))
1349 playernumber = playernumber * 10 + (*p1 - '0');
1357 playername_start = p1;
1358 while (p1 < p2 && *p1 != '"')
1360 playername_length = p1 - playername_start;
1366 playername_start = p1;
1367 while (p1 < p2 && *p1 != ' ')
1369 playername_length = p1 - playername_start;
1371 while (p1 < p2 && *p1 == ' ')
1373 if(playername_start)
1375 // set playernumber to the right client
1377 if(playername_length >= sizeof(namebuf))
1380 Con_Print("Host_Tell: too long player name/ID\n");
1382 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1385 memcpy(namebuf, playername_start, playername_length);
1386 namebuf[playername_length] = 0;
1387 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1389 if (!svs.clients[playernumber].active)
1391 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1395 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1398 Con_Print("Host_Tell: invalid player name/ID\n");
1400 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1403 // remove trailing newlines
1404 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1406 // remove quotes if present
1412 else if (fromServer)
1413 Con_Print("Host_Tell: missing end quote\n");
1415 SV_ClientPrint("Host_Tell: missing end quote\n");
1417 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1420 return; // empty say
1421 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1427 host_client = svs.clients + playernumber;
1428 SV_ClientPrint(text);
1438 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1439 void Host_Color(int changetop, int changebottom)
1441 int top, bottom, playercolor;
1443 // get top and bottom either from the provided values or the current values
1444 // (allows changing only top or bottom, or both at once)
1445 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1446 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1450 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1456 playercolor = top*16 + bottom;
1458 if (cmd_source == src_command)
1460 Cvar_SetValueQuick(&cl_color, playercolor);
1464 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1467 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1469 Con_DPrint("Calling SV_ChangeTeam\n");
1470 prog->globals.server->time = sv.time;
1471 prog->globals.generic[OFS_PARM0] = playercolor;
1472 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1473 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1478 if (host_client->edict)
1480 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1481 val->_float = playercolor;
1482 host_client->edict->fields.server->team = bottom + 1;
1484 host_client->colors = playercolor;
1485 if (host_client->old_colors != host_client->colors)
1487 host_client->old_colors = host_client->colors;
1488 // send notification to all clients
1489 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1490 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1491 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1496 void Host_Color_f(void)
1500 if (Cmd_Argc() == 1)
1502 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1503 Con_Print("color <0-15> [0-15]\n");
1507 if (Cmd_Argc() == 2)
1508 top = bottom = atoi(Cmd_Argv(1));
1511 top = atoi(Cmd_Argv(1));
1512 bottom = atoi(Cmd_Argv(2));
1514 Host_Color(top, bottom);
1517 void Host_TopColor_f(void)
1519 if (Cmd_Argc() == 1)
1521 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1522 Con_Print("topcolor <0-15>\n");
1526 Host_Color(atoi(Cmd_Argv(1)), -1);
1529 void Host_BottomColor_f(void)
1531 if (Cmd_Argc() == 1)
1533 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1534 Con_Print("bottomcolor <0-15>\n");
1538 Host_Color(-1, atoi(Cmd_Argv(1)));
1541 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1542 void Host_Rate_f(void)
1546 if (Cmd_Argc() != 2)
1548 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1549 Con_Print("rate <bytespersecond>\n");
1553 rate = atoi(Cmd_Argv(1));
1555 if (cmd_source == src_command)
1557 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1561 host_client->rate = rate;
1569 void Host_Kill_f (void)
1571 if (host_client->edict->fields.server->health <= 0)
1573 SV_ClientPrint("Can't suicide -- already dead!\n");
1577 prog->globals.server->time = sv.time;
1578 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1579 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1588 void Host_Pause_f (void)
1590 if (!pausable.integer)
1591 SV_ClientPrint("Pause not allowed.\n");
1595 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1596 // send notification to all clients
1597 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1598 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1603 ======================
1605 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1606 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1607 ======================
1609 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)"};
1610 static void Host_PModel_f (void)
1615 if (Cmd_Argc () == 1)
1617 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1620 i = atoi(Cmd_Argv(1));
1622 if (cmd_source == src_command)
1624 if (cl_pmodel.integer == i)
1626 Cvar_SetValue ("_cl_pmodel", i);
1627 if (cls.state == ca_connected)
1628 Cmd_ForwardToServer ();
1632 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1636 //===========================================================================
1644 void Host_PreSpawn_f (void)
1646 if (host_client->spawned)
1648 Con_Print("prespawn not valid -- already spawned\n");
1652 if (host_client->netconnection)
1654 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1655 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1656 MSG_WriteByte (&host_client->netconnection->message, 2);
1657 host_client->sendsignon = 0; // enable unlimited sends again
1660 // reset the name change timer because the client will send name soon
1661 host_client->nametime = 0;
1669 void Host_Spawn_f (void)
1673 int stats[MAX_CL_STATS];
1675 if (host_client->spawned)
1677 Con_Print("Spawn not valid -- already spawned\n");
1681 // reset name change timer again because they might want to change name
1682 // again in the first 5 seconds after connecting
1683 host_client->nametime = 0;
1685 // LordHavoc: moved this above the QC calls at FrikaC's request
1686 // LordHavoc: commented this out
1687 //if (host_client->netconnection)
1688 // SZ_Clear (&host_client->netconnection->message);
1690 // run the entrance script
1693 // loaded games are fully initialized already
1694 if (prog->funcoffsets.RestoreGame)
1696 Con_DPrint("Calling RestoreGame\n");
1697 prog->globals.server->time = sv.time;
1698 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1699 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1704 //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);
1706 // copy spawn parms out of the client_t
1707 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1708 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1710 // call the spawn function
1711 host_client->clientconnectcalled = true;
1712 prog->globals.server->time = sv.time;
1713 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1714 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1716 if (cls.state == ca_dedicated)
1717 Con_Printf("%s connected\n", host_client->name);
1719 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1722 if (!host_client->netconnection)
1725 // send time of update
1726 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1727 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1729 // send all current names, colors, and frag counts
1730 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1732 if (!client->active)
1734 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1735 MSG_WriteByte (&host_client->netconnection->message, i);
1736 MSG_WriteString (&host_client->netconnection->message, client->name);
1737 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1738 MSG_WriteByte (&host_client->netconnection->message, i);
1739 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1740 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1741 MSG_WriteByte (&host_client->netconnection->message, i);
1742 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1745 // send all current light styles
1746 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1748 if (sv.lightstyles[i][0])
1750 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1751 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1752 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1757 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1758 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1759 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1761 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1762 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1763 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1765 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1766 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1767 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1769 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1770 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1771 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1774 // Never send a roll angle, because savegames can catch the server
1775 // in a state where it is expecting the client to correct the angle
1776 // and it won't happen if the game was just loaded, so you wind up
1777 // with a permanent head tilt
1780 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1781 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1782 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1783 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1787 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1788 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1789 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1790 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1793 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1795 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1796 MSG_WriteByte (&host_client->netconnection->message, 3);
1804 void Host_Begin_f (void)
1806 host_client->spawned = true;
1808 // LordHavoc: note: this code also exists in SV_DropClient
1812 for (i = 0;i < svs.maxclients;i++)
1813 if (svs.clients[i].active && !svs.clients[i].spawned)
1815 if (i == svs.maxclients)
1817 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1818 sv.paused = sv.loadgame = false; // we're basically done with loading now
1823 //===========================================================================
1830 Kicks a user off of the server
1833 void Host_Kick_f (void)
1836 const char *message = NULL;
1839 qboolean byNumber = false;
1847 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1849 i = (int)(atof(Cmd_Argv(2)) - 1);
1850 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1856 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1858 if (!host_client->active)
1860 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1865 if (i < svs.maxclients)
1867 if (cmd_source == src_command)
1869 if (cls.state == ca_dedicated)
1872 who = cl_name.string;
1877 // can't kick yourself!
1878 if (host_client == save)
1883 message = Cmd_Args();
1884 COM_ParseToken_Simple(&message, false, false);
1887 message++; // skip the #
1888 while (*message == ' ') // skip white space
1890 message += strlen(Cmd_Argv(2)); // skip the number
1892 while (*message && *message == ' ')
1896 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1898 SV_ClientPrintf("Kicked by %s\n", who);
1899 SV_DropClient (false); // kicked
1907 ===============================================================================
1911 ===============================================================================
1919 void Host_Give_f (void)
1927 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1932 v = atoi (Cmd_Argv(2));
1946 // MED 01/04/97 added hipnotic give stuff
1947 if (gamemode == GAME_HIPNOTIC)
1952 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1954 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1956 else if (t[0] == '9')
1957 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1958 else if (t[0] == '0')
1959 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1960 else if (t[0] >= '2')
1961 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1966 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1971 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1974 host_client->edict->fields.server->ammo_shells = v;
1977 if (gamemode == GAME_ROGUE)
1979 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1982 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1983 host_client->edict->fields.server->ammo_nails = v;
1988 host_client->edict->fields.server->ammo_nails = v;
1992 if (gamemode == GAME_ROGUE)
1994 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1998 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1999 host_client->edict->fields.server->ammo_nails = v;
2004 if (gamemode == GAME_ROGUE)
2006 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
2010 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2011 host_client->edict->fields.server->ammo_rockets = v;
2016 host_client->edict->fields.server->ammo_rockets = v;
2020 if (gamemode == GAME_ROGUE)
2022 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2026 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2027 host_client->edict->fields.server->ammo_rockets = v;
2032 host_client->edict->fields.server->health = v;
2035 if (gamemode == GAME_ROGUE)
2037 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2041 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2042 host_client->edict->fields.server->ammo_cells = v;
2047 host_client->edict->fields.server->ammo_cells = v;
2051 if (gamemode == GAME_ROGUE)
2053 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2057 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2058 host_client->edict->fields.server->ammo_cells = v;
2065 prvm_edict_t *FindViewthing (void)
2070 for (i=0 ; i<prog->num_edicts ; i++)
2072 e = PRVM_EDICT_NUM(i);
2073 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2076 Con_Print("No viewthing on map\n");
2085 void Host_Viewmodel_f (void)
2094 e = FindViewthing ();
2099 m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
2100 if (!m || !m->loaded || !m->Draw)
2102 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2106 e->fields.server->frame = 0;
2107 cl.model_precache[(int)e->fields.server->modelindex] = m;
2115 void Host_Viewframe_f (void)
2125 e = FindViewthing ();
2129 m = cl.model_precache[(int)e->fields.server->modelindex];
2131 f = atoi(Cmd_Argv(1));
2132 if (f >= m->numframes)
2135 e->fields.server->frame = f;
2139 void PrintFrameName (dp_model_t *m, int frame)
2142 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2144 Con_Printf("frame %i\n", frame);
2152 void Host_Viewnext_f (void)
2161 e = FindViewthing ();
2165 m = cl.model_precache[(int)e->fields.server->modelindex];
2167 e->fields.server->frame = e->fields.server->frame + 1;
2168 if (e->fields.server->frame >= m->numframes)
2169 e->fields.server->frame = m->numframes - 1;
2171 PrintFrameName (m, (int)e->fields.server->frame);
2179 void Host_Viewprev_f (void)
2188 e = FindViewthing ();
2193 m = cl.model_precache[(int)e->fields.server->modelindex];
2195 e->fields.server->frame = e->fields.server->frame - 1;
2196 if (e->fields.server->frame < 0)
2197 e->fields.server->frame = 0;
2199 PrintFrameName (m, (int)e->fields.server->frame);
2203 ===============================================================================
2207 ===============================================================================
2216 void Host_Startdemos_f (void)
2220 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2226 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2229 Con_DPrintf("%i demo(s) in loop\n", c);
2231 for (i=1 ; i<c+1 ; i++)
2232 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2234 // LordHavoc: clear the remaining slots
2235 for (;i <= MAX_DEMOS;i++)
2236 cls.demos[i-1][0] = 0;
2238 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2252 Return to looping demos
2255 void Host_Demos_f (void)
2257 if (cls.state == ca_dedicated)
2259 if (cls.demonum == -1)
2269 Return to looping demos
2272 void Host_Stopdemo_f (void)
2274 if (!cls.demoplayback)
2277 Host_ShutdownServer ();
2280 void Host_SendCvar_f (void)
2284 const char *cvarname;
2289 cvarname = Cmd_Argv(1);
2290 if (cls.state == ca_connected)
2292 c = Cvar_FindVar(cvarname);
2293 // LordHavoc: if there is no such cvar or if it is private, send a
2294 // reply indicating that it has no value
2295 if(!c || (c->flags & CVAR_PRIVATE))
2296 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2298 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2301 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2305 if (cls.state != ca_dedicated)
2309 for(;i<svs.maxclients;i++)
2310 if(svs.clients[i].active && svs.clients[i].netconnection)
2312 host_client = &svs.clients[i];
2313 Host_ClientCommands("sendcvar %s\n", cvarname);
2318 static void MaxPlayers_f(void)
2322 if (Cmd_Argc() != 2)
2324 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
2330 Con_Print("maxplayers can not be changed while a server is running.\n");
2331 Con_Print("It will be changed on next server startup (\"map\" command).\n");
2334 n = atoi(Cmd_Argv(1));
2335 n = bound(1, n, MAX_SCOREBOARD);
2336 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2338 svs.maxclients_next = n;
2340 Cvar_Set ("deathmatch", "0");
2342 Cvar_Set ("deathmatch", "1");
2345 //=============================================================================
2347 // QuakeWorld commands
2350 =====================
2353 Send the rest of the command line over as
2354 an unconnected command.
2355 =====================
2357 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2361 lhnetsocket_t *mysocket;
2363 if (!rcon_password.string || !rcon_password.string[0])
2365 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2369 for (i = 0;rcon_password.string[i];i++)
2371 if (ISWHITESPACE(rcon_password.string[i]))
2373 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2379 to = cls.netcon->peeraddress;
2382 if (!rcon_address.string[0])
2384 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2387 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2389 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2392 // simply put together the rcon packet and send it
2393 if(rcon_secure.integer)
2397 dpsnprintf(argbuf, sizeof(argbuf), "%ld %s", (long) time(NULL), Cmd_Args());
2398 memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24);
2399 if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, strlen(rcon_password.string)))
2402 strlcpy(buf + 41, argbuf, sizeof(buf) - 41);
2403 NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to);
2408 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2414 ====================
2417 user <name or userid>
2419 Dump userdata / masterdata for a user
2420 ====================
2422 void Host_User_f (void) // credit: taken from QuakeWorld
2427 if (Cmd_Argc() != 2)
2429 Con_Printf ("Usage: user <username / userid>\n");
2433 uid = atoi(Cmd_Argv(1));
2435 for (i = 0;i < cl.maxclients;i++)
2437 if (!cl.scores[i].name[0])
2439 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2441 InfoString_Print(cl.scores[i].qw_userinfo);
2445 Con_Printf ("User not in server.\n");
2449 ====================
2452 Dump userids for all current players
2453 ====================
2455 void Host_Users_f (void) // credit: taken from QuakeWorld
2461 Con_Printf ("userid frags name\n");
2462 Con_Printf ("------ ----- ----\n");
2463 for (i = 0;i < cl.maxclients;i++)
2465 if (cl.scores[i].name[0])
2467 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2472 Con_Printf ("%i total users\n", c);
2477 Host_FullServerinfo_f
2479 Sent by server when serverinfo changes
2482 // TODO: shouldn't this be a cvar instead?
2483 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2486 if (Cmd_Argc() != 2)
2488 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2492 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2493 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2494 cl.qw_teamplay = atoi(temp);
2501 Allow clients to change userinfo
2505 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2512 if (Cmd_Argc() != 2)
2514 Con_Printf ("fullinfo <complete info string>\n");
2524 while (*s && *s != '\\')
2530 Con_Printf ("MISSING VALUE\n");
2536 while (*s && *s != '\\')
2543 CL_SetInfo(key, value, false, false, false, false);
2551 Allow clients to change userinfo
2554 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2556 if (Cmd_Argc() == 1)
2558 InfoString_Print(cls.userinfo);
2561 if (Cmd_Argc() != 3)
2563 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2566 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2570 ====================
2573 packet <destination> <contents>
2575 Contents allows \n escape character
2576 ====================
2578 void Host_Packet_f (void) // credit: taken from QuakeWorld
2584 lhnetaddress_t address;
2585 lhnetsocket_t *mysocket;
2587 if (Cmd_Argc() != 3)
2589 Con_Printf ("packet <destination> <contents>\n");
2593 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2595 Con_Printf ("Bad address\n");
2601 send[0] = send[1] = send[2] = send[3] = 0xff;
2603 l = (int)strlen (in);
2604 for (i=0 ; i<l ; i++)
2606 if (out >= send + sizeof(send) - 1)
2608 if (in[i] == '\\' && in[i+1] == 'n')
2613 else if (in[i] == '\\' && in[i+1] == '0')
2618 else if (in[i] == '\\' && in[i+1] == 't')
2623 else if (in[i] == '\\' && in[i+1] == 'r')
2628 else if (in[i] == '\\' && in[i+1] == '"')
2637 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2639 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2641 NetConn_Write(mysocket, send, out - send, &address);
2645 ====================
2648 Send back ping and packet loss update for all current players to this player
2649 ====================
2651 void Host_Pings_f (void)
2653 int i, j, ping, packetloss;
2656 if (!host_client->netconnection)
2659 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2661 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2662 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2664 for (i = 0;i < svs.maxclients;i++)
2667 if (svs.clients[i].netconnection)
2668 for (j = 0;j < NETGRAPH_PACKETS;j++)
2669 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2671 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2672 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2673 ping = bound(0, ping, 9999);
2674 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2676 // send qw_svc_updateping and qw_svc_updatepl messages
2677 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2678 MSG_WriteShort(&host_client->netconnection->message, ping);
2679 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2680 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2684 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2685 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2686 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2689 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2690 MSG_WriteString(&host_client->netconnection->message, "\n");
2693 void Host_PingPLReport_f(void)
2697 if (l > cl.maxclients)
2699 for (i = 0;i < l;i++)
2701 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2702 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2706 //=============================================================================
2713 void Host_InitCommands (void)
2715 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2717 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2718 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2719 if (gamemode == GAME_NEHAHRA)
2721 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2722 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2723 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2724 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2725 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2729 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2730 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2731 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2732 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2733 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2735 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2736 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2737 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2738 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2739 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)");
2740 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2741 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2742 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2743 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2744 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2745 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2746 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2747 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2748 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2749 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2751 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2752 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2753 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2755 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2756 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2757 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2758 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2760 Cvar_RegisterVariable (&cl_name);
2761 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2762 Cvar_RegisterVariable (&cl_color);
2763 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2764 Cvar_RegisterVariable (&cl_rate);
2765 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2766 if (gamemode == GAME_NEHAHRA)
2768 Cvar_RegisterVariable (&cl_pmodel);
2769 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2772 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2773 Cvar_RegisterVariable (&cl_playermodel);
2774 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2775 Cvar_RegisterVariable (&cl_playerskin);
2776 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2778 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2779 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2780 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)");
2781 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2783 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2785 Cvar_RegisterVariable (&rcon_password);
2786 Cvar_RegisterVariable (&rcon_address);
2787 Cvar_RegisterVariable (&rcon_secure);
2788 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)");
2789 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2790 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2791 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2792 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2793 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2794 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2795 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2796 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2798 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)");
2799 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)");
2801 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)");
2802 Cvar_RegisterVariable (&r_fixtrans_auto);
2804 Cvar_RegisterVariable (&team);
2805 Cvar_RegisterVariable (&skin);
2806 Cvar_RegisterVariable (&noaim);
2808 Cvar_RegisterVariable(&sv_cheats);
2809 Cvar_RegisterVariable(&sv_adminnick);
2810 Cvar_RegisterVariable(&sv_status_privacy);
2811 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2814 void Host_NoOperation_f(void)