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.
26 cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
27 cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
28 cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
29 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."};
30 cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands"};
31 cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
32 cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
33 cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
34 cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
35 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)"};
36 qboolean allowcheats = false;
38 extern qboolean host_shuttingdown;
39 extern cvar_t developer_entityparsing;
47 void Host_Quit_f (void)
50 Con_Printf("shutting down already!\n");
60 void Host_Status_f (void)
64 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
65 void (*print) (const char *fmt, ...);
69 if (cmd_source == src_command)
71 // if running a client, try to send over network so the client's status report parser will see the report
72 if (cls.state == ca_connected)
74 Cmd_ForwardToServer ();
80 print = SV_ClientPrintf;
85 if(cmd_source == src_command)
91 if (strcmp(Cmd_Argv(1), "1") == 0)
93 else if (strcmp(Cmd_Argv(1), "2") == 0)
97 for (players = 0, i = 0;i < svs.maxclients;i++)
98 if (svs.clients[i].active)
100 print ("host: %s\n", Cvar_VariableString ("hostname"));
101 print ("version: %s build %s\n", gamename, buildstring);
102 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
103 print ("map: %s\n", sv.name);
104 print ("timing: %s\n", Host_TimingReport());
105 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
108 print ("^2IP %%pl ping time frags no name\n");
110 print ("^5IP no name\n");
112 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
119 if (in == 0 || in == 1)
121 seconds = (int)(realtime - client->connecttime);
122 minutes = seconds / 60;
125 seconds -= (minutes * 60);
126 hours = minutes / 60;
128 minutes -= (hours * 60);
134 if (client->netconnection)
135 for (j = 0;j < NETGRAPH_PACKETS;j++)
136 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
138 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
139 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
142 if(sv_status_privacy.integer && cmd_source != src_command)
143 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
145 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
147 frags = client->frags;
149 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
151 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
157 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
158 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
162 frags = atoi(qcstatus);
166 if (in == 0) // default layout
168 print ("#%-3u ", i+1);
169 print ("%-16.16s ", client->name);
170 print ("%4i ", frags);
171 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
174 else if (in == 1) // extended layout
176 k%2 ? print("^3") : print("^7");
177 print ("%-21s ", ip);
178 print ("%2i ", packetloss);
179 print ("%4i ", ping);
180 print ("%2i:%02i:%02i ", hours, minutes, seconds);
181 print ("%4i ", frags);
182 print ("#%-3u ", i+1);
183 print ("^7%s\n", client->name);
185 else if (in == 2) // reduced layout
187 k%2 ? print("^3") : print("^7");
188 print ("%-21s ", ip);
189 print ("#%-3u ", i+1);
190 print ("^7%s\n", client->name);
194 if(cmd_source == src_command)
203 Sets client to godmode
206 void Host_God_f (void)
210 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
214 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
215 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
216 SV_ClientPrint("godmode OFF\n");
218 SV_ClientPrint("godmode ON\n");
221 void Host_Notarget_f (void)
225 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
229 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
230 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
231 SV_ClientPrint("notarget OFF\n");
233 SV_ClientPrint("notarget ON\n");
236 qboolean noclip_anglehack;
238 void Host_Noclip_f (void)
242 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
246 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
248 noclip_anglehack = true;
249 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
250 SV_ClientPrint("noclip ON\n");
254 noclip_anglehack = false;
255 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
256 SV_ClientPrint("noclip OFF\n");
264 Sets client to flymode
267 void Host_Fly_f (void)
271 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
275 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
277 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
278 SV_ClientPrint("flymode ON\n");
282 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
283 SV_ClientPrint("flymode OFF\n");
294 void Host_Pings_f (void); // called by Host_Ping_f
295 void Host_Ping_f (void)
299 void (*print) (const char *fmt, ...);
301 if (cmd_source == src_command)
303 // if running a client, try to send over network so the client's ping report parser will see the report
304 if (cls.state == ca_connected)
306 Cmd_ForwardToServer ();
312 print = SV_ClientPrintf;
317 print("Client ping times:\n");
318 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
322 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
325 // 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)
326 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
331 ===============================================================================
335 ===============================================================================
339 ======================
344 command from the console. Active clients are kicked off.
345 ======================
347 void Host_Map_f (void)
349 char level[MAX_QPATH];
353 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
357 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
358 if (gamemode == GAME_DELUXEQUAKE)
359 Cvar_Set("warpmark", "");
361 cls.demonum = -1; // stop demo loop in case this fails
364 Host_ShutdownServer();
366 if(svs.maxclients != svs.maxclients_next)
368 svs.maxclients = svs.maxclients_next;
370 Mem_Free(svs.clients);
371 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
377 svs.serverflags = 0; // haven't completed an episode yet
378 allowcheats = sv_cheats.integer != 0;
379 strlcpy(level, Cmd_Argv(1), sizeof(level));
380 SV_SpawnServer(level);
381 if (sv.active && cls.state == ca_disconnected)
382 CL_EstablishConnection("local:1");
389 Goes to a new map, taking all clients along
392 void Host_Changelevel_f (void)
394 char level[MAX_QPATH];
398 Con_Print("changelevel <levelname> : continue game on a new level\n");
411 SV_SaveSpawnparms ();
413 allowcheats = sv_cheats.integer != 0;
414 strlcpy(level, Cmd_Argv(1), sizeof(level));
415 SV_SpawnServer(level);
416 if (sv.active && cls.state == ca_disconnected)
417 CL_EstablishConnection("local:1");
424 Restarts the current server for a dead player
427 void Host_Restart_f (void)
429 char mapname[MAX_QPATH];
433 Con_Print("restart : restart current level\n");
438 Con_Print("Only the server may restart\n");
445 allowcheats = sv_cheats.integer != 0;
446 strlcpy(mapname, sv.name, sizeof(mapname));
447 SV_SpawnServer(mapname);
448 if (sv.active && cls.state == ca_disconnected)
449 CL_EstablishConnection("local:1");
456 This command causes the client to wait for the signon messages again.
457 This is sent just before a server changes levels
460 void Host_Reconnect_f (void)
463 // if not connected, reconnect to the most recent server
466 // if we have connected to a server recently, the userinfo
467 // will still contain its IP address, so get the address...
468 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
470 CL_EstablishConnection(temp);
472 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
475 // if connected, do something based on protocol
476 if (cls.protocol == PROTOCOL_QUAKEWORLD)
478 // quakeworld can just re-login
479 if (cls.qw_downloadmemory) // don't change when downloading
484 if (cls.state == ca_connected && cls.signon < SIGNONS)
486 Con_Printf("reconnecting...\n");
487 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
488 MSG_WriteString(&cls.netcon->message, "new");
493 // netquake uses reconnect on level changes (silly)
496 Con_Print("reconnect : wait for signon messages again\n");
501 Con_Print("reconnect: no signon, ignoring reconnect\n");
504 cls.signon = 0; // need new connection messages
509 =====================
512 User command to connect to server
513 =====================
515 void Host_Connect_f (void)
519 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
522 CL_EstablishConnection(Cmd_Argv(1));
527 ===============================================================================
531 ===============================================================================
534 #define SAVEGAME_VERSION 5
536 void Host_Savegame_to (const char *name)
539 int i, lightstyles = 64;
540 char comment[SAVEGAME_COMMENT_LENGTH+1];
543 // first we have to figure out if this can be saved in 64 lightstyles
544 // (for Quake compatibility)
545 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
546 if (sv.lightstyles[i][0])
549 isserver = !strcmp(PRVM_NAME, "server");
551 Con_Printf("Saving game to %s...\n", name);
552 f = FS_OpenRealFile(name, "wb", false);
555 Con_Print("ERROR: couldn't open.\n");
559 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
561 memset(comment, 0, sizeof(comment));
563 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);
565 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
566 // convert space to _ to make stdio happy
567 // LordHavoc: convert control characters to _ as well
568 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
569 if (ISWHITESPACEORCONTROL(comment[i]))
571 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
573 FS_Printf(f, "%s\n", comment);
576 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
577 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
578 FS_Printf(f, "%d\n", current_skill);
579 FS_Printf(f, "%s\n", sv.name);
580 FS_Printf(f, "%f\n",sv.time);
584 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
585 FS_Printf(f, "(dummy)\n");
586 FS_Printf(f, "%d\n", 0);
587 FS_Printf(f, "%s\n", "(dummy)");
588 FS_Printf(f, "%f\n", realtime);
591 // write the light styles
592 for (i=0 ; i<lightstyles ; i++)
594 if (isserver && sv.lightstyles[i][0])
595 FS_Printf(f, "%s\n", sv.lightstyles[i]);
600 PRVM_ED_WriteGlobals (f);
601 for (i=0 ; i<prog->num_edicts ; i++)
603 FS_Printf(f,"// edict %d\n", i);
604 //Con_Printf("edict %d...\n", i);
605 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
610 FS_Printf(f,"// DarkPlaces extended savegame\n");
611 // darkplaces extension - extra lightstyles, support for color lightstyles
612 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
613 if (isserver && sv.lightstyles[i][0])
614 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
616 // darkplaces extension - model precaches
617 for (i=1 ; i<MAX_MODELS ; i++)
618 if (sv.model_precache[i][0])
619 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
621 // darkplaces extension - sound precaches
622 for (i=1 ; i<MAX_SOUNDS ; i++)
623 if (sv.sound_precache[i][0])
624 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
629 Con_Print("done.\n");
637 void Host_Savegame_f (void)
639 char name[MAX_QPATH];
643 Con_Print("Can't save - no server running.\n");
649 // singleplayer checks
652 Con_Print("Can't save in intermission.\n");
656 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
658 Con_Print("Can't savegame with a dead player\n");
663 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");
667 Con_Print("save <savename> : save a game\n");
671 if (strstr(Cmd_Argv(1), ".."))
673 Con_Print("Relative pathnames are not allowed.\n");
677 strlcpy (name, Cmd_Argv(1), sizeof (name));
678 FS_DefaultExtension (name, ".sav", sizeof (name));
681 Host_Savegame_to(name);
691 void Host_Loadgame_f (void)
693 char filename[MAX_QPATH];
694 char mapname[MAX_QPATH];
704 float spawn_parms[NUM_SPAWN_PARMS];
708 Con_Print("load <savename> : load a game\n");
712 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
713 FS_DefaultExtension (filename, ".sav", sizeof (filename));
715 Con_Printf("Loading game from %s...\n", filename);
717 // stop playing demos
718 if (cls.demoplayback)
724 cls.demonum = -1; // stop demo loop in case this fails
726 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
729 Con_Print("ERROR: couldn't open.\n");
733 if(developer_entityparsing.integer)
734 Con_Printf("Host_Loadgame_f: loading version\n");
737 COM_ParseToken_Simple(&t, false, false);
738 version = atoi(com_token);
739 if (version != SAVEGAME_VERSION)
742 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
746 if(developer_entityparsing.integer)
747 Con_Printf("Host_Loadgame_f: loading description\n");
750 COM_ParseToken_Simple(&t, false, false);
752 for (i = 0;i < NUM_SPAWN_PARMS;i++)
754 COM_ParseToken_Simple(&t, false, false);
755 spawn_parms[i] = atof(com_token);
758 COM_ParseToken_Simple(&t, false, false);
759 // this silliness is so we can load 1.06 save files, which have float skill values
760 current_skill = (int)(atof(com_token) + 0.5);
761 Cvar_SetValue ("skill", (float)current_skill);
763 if(developer_entityparsing.integer)
764 Con_Printf("Host_Loadgame_f: loading mapname\n");
767 COM_ParseToken_Simple(&t, false, false);
768 strlcpy (mapname, com_token, sizeof(mapname));
770 if(developer_entityparsing.integer)
771 Con_Printf("Host_Loadgame_f: loading time\n");
774 COM_ParseToken_Simple(&t, false, false);
775 time = atof(com_token);
777 allowcheats = sv_cheats.integer != 0;
779 if(developer_entityparsing.integer)
780 Con_Printf("Host_Loadgame_f: spawning server\n");
782 SV_SpawnServer (mapname);
786 Con_Print("Couldn't load map\n");
789 sv.paused = true; // pause until all clients connect
792 if(developer_entityparsing.integer)
793 Con_Printf("Host_Loadgame_f: loading light styles\n");
795 // load the light styles
801 for (i = 0;i < MAX_LIGHTSTYLES;i++)
805 COM_ParseToken_Simple(&t, false, false);
806 // if this is a 64 lightstyle savegame produced by Quake, stop now
807 // we have to check this because darkplaces may save more than 64
808 if (com_token[0] == '{')
813 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
816 if(developer_entityparsing.integer)
817 Con_Printf("Host_Loadgame_f: skipping until globals\n");
819 // now skip everything before the first opening brace
820 // (this is for forward compatibility, so that older versions (at
821 // least ones with this fix) can load savegames with extra data before the
822 // first brace, as might be produced by a later engine version)
826 if (!COM_ParseToken_Simple(&t, false, false))
828 if (com_token[0] == '{')
835 // load the edicts out of the savegame file
840 while (COM_ParseToken_Simple(&t, false, false))
841 if (!strcmp(com_token, "}"))
843 if (!COM_ParseToken_Simple(&start, false, false))
848 if (strcmp(com_token,"{"))
851 Host_Error ("First token isn't a brace");
856 if(developer_entityparsing.integer)
857 Con_Printf("Host_Loadgame_f: loading globals\n");
859 // parse the global vars
860 PRVM_ED_ParseGlobals (start);
865 if (entnum >= MAX_EDICTS)
868 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
870 while (entnum >= prog->max_edicts)
871 PRVM_MEM_IncreaseEdicts();
872 ent = PRVM_EDICT_NUM(entnum);
873 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
874 ent->priv.server->free = false;
876 if(developer_entityparsing.integer)
877 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
879 PRVM_ED_ParseEdict (start, ent);
881 // link it into the bsp tree
882 if (!ent->priv.server->free)
883 SV_LinkEdict (ent, false);
890 prog->num_edicts = entnum;
893 for (i = 0;i < NUM_SPAWN_PARMS;i++)
894 svs.clients[0].spawn_parms[i] = spawn_parms[i];
896 if(developer_entityparsing.integer)
897 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
899 // read extended data if present
900 // the extended data is stored inside a /* */ comment block, which the
901 // parser intentionally skips, so we have to check for it manually here
904 while (*end == '\r' || *end == '\n')
906 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
908 if(developer_entityparsing.integer)
909 Con_Printf("Host_Loadgame_f: loading extended data\n");
911 Con_Printf("Loading extended DarkPlaces savegame\n");
913 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
914 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
915 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
916 while (COM_ParseToken_Simple(&t, false, false))
918 if (!strcmp(com_token, "sv.lightstyles"))
920 COM_ParseToken_Simple(&t, false, false);
922 COM_ParseToken_Simple(&t, false, false);
923 if (i >= 0 && i < MAX_LIGHTSTYLES)
924 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
926 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
928 else if (!strcmp(com_token, "sv.model_precache"))
930 COM_ParseToken_Simple(&t, false, false);
932 COM_ParseToken_Simple(&t, false, false);
933 if (i >= 0 && i < MAX_MODELS)
935 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
936 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
939 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
941 else if (!strcmp(com_token, "sv.sound_precache"))
943 COM_ParseToken_Simple(&t, false, false);
945 COM_ParseToken_Simple(&t, false, false);
946 if (i >= 0 && i < MAX_SOUNDS)
947 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
949 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
951 // skip any trailing text or unrecognized commands
952 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
959 if(developer_entityparsing.integer)
960 Con_Printf("Host_Loadgame_f: finished\n");
964 // make sure we're connected to loopback
965 if (sv.active && cls.state == ca_disconnected)
966 CL_EstablishConnection("local:1");
969 //============================================================================
972 ======================
974 ======================
976 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
977 void Host_Name_f (void)
980 qboolean valid_colors;
981 char newName[sizeof(host_client->name)];
983 if (Cmd_Argc () == 1)
985 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
989 if (Cmd_Argc () == 2)
990 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
992 strlcpy (newName, Cmd_Args(), sizeof (newName));
994 if (cmd_source == src_command)
996 Cvar_Set ("_cl_name", newName);
1000 if (realtime < host_client->nametime)
1002 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1006 host_client->nametime = realtime + 5;
1008 // point the string back at updateclient->name to keep it safe
1009 strlcpy (host_client->name, newName, sizeof (host_client->name));
1011 for (i = 0, j = 0;host_client->name[i];i++)
1012 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1013 host_client->name[j++] = host_client->name[i];
1014 host_client->name[j] = 0;
1016 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1017 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1019 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1020 host_client->name[sizeof(host_client->name) - 1] = 0;
1021 host_client->name[0] = STRING_COLOR_TAG;
1022 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1025 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1026 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1029 l = strlen(host_client->name);
1030 if(l < sizeof(host_client->name) - 1)
1032 // duplicate the color tag to escape it
1033 host_client->name[i] = STRING_COLOR_TAG;
1034 host_client->name[i+1] = 0;
1035 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1039 // remove the last character to fix the color code
1040 host_client->name[l-1] = 0;
1041 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1045 // find the last color tag offset and decide if we need to add a reset tag
1046 for (i = 0, j = -1;host_client->name[i];i++)
1048 if (host_client->name[i] == STRING_COLOR_TAG)
1050 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1053 // if this happens to be a reset tag then we don't need one
1054 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1059 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]))
1065 if (host_client->name[i+1] == STRING_COLOR_TAG)
1072 // does not end in the default color string, so add it
1073 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1074 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1076 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1077 if (strcmp(host_client->old_name, host_client->name))
1079 if (host_client->spawned)
1080 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1081 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1082 // send notification to all clients
1083 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1084 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1085 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1086 SV_WriteNetnameIntoDemo(host_client);
1091 ======================
1093 ======================
1095 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1096 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1097 void Host_Playermodel_f (void)
1100 char newPath[sizeof(host_client->playermodel)];
1102 if (Cmd_Argc () == 1)
1104 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1108 if (Cmd_Argc () == 2)
1109 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1111 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1113 for (i = 0, j = 0;newPath[i];i++)
1114 if (newPath[i] != '\r' && newPath[i] != '\n')
1115 newPath[j++] = newPath[i];
1118 if (cmd_source == src_command)
1120 Cvar_Set ("_cl_playermodel", newPath);
1125 if (realtime < host_client->nametime)
1127 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1131 host_client->nametime = realtime + 5;
1134 // point the string back at updateclient->name to keep it safe
1135 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1136 if( prog->fieldoffsets.playermodel >= 0 )
1137 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1138 if (strcmp(host_client->old_model, host_client->playermodel))
1140 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1141 /*// send notification to all clients
1142 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1143 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1144 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1149 ======================
1151 ======================
1153 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1154 void Host_Playerskin_f (void)
1157 char newPath[sizeof(host_client->playerskin)];
1159 if (Cmd_Argc () == 1)
1161 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1165 if (Cmd_Argc () == 2)
1166 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1168 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1170 for (i = 0, j = 0;newPath[i];i++)
1171 if (newPath[i] != '\r' && newPath[i] != '\n')
1172 newPath[j++] = newPath[i];
1175 if (cmd_source == src_command)
1177 Cvar_Set ("_cl_playerskin", newPath);
1182 if (realtime < host_client->nametime)
1184 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1188 host_client->nametime = realtime + 5;
1191 // point the string back at updateclient->name to keep it safe
1192 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1193 if( prog->fieldoffsets.playerskin >= 0 )
1194 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1195 if (strcmp(host_client->old_skin, host_client->playerskin))
1197 //if (host_client->spawned)
1198 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1199 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1200 /*// send notification to all clients
1201 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1202 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1203 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1207 void Host_Version_f (void)
1209 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1212 void Host_Say(qboolean teamonly)
1218 // LordHavoc: long say messages
1220 qboolean fromServer = false;
1222 if (cmd_source == src_command)
1224 if (cls.state == ca_dedicated)
1231 Cmd_ForwardToServer ();
1236 if (Cmd_Argc () < 2)
1239 if (!teamplay.integer)
1249 // note this uses the chat prefix \001
1250 if (!fromServer && !teamonly)
1251 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1252 else if (!fromServer && teamonly)
1253 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1254 else if(*(sv_adminnick.string))
1255 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1257 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1258 p2 = text + strlen(text);
1259 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1261 if (p2[-1] == '\"' && quoted)
1266 strlcat(text, "\n", sizeof(text));
1268 // note: save is not a valid edict if fromServer is true
1270 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1271 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1272 SV_ClientPrint(text);
1275 if (cls.state == ca_dedicated)
1276 Con_Print(&text[1]);
1280 void Host_Say_f(void)
1286 void Host_Say_Team_f(void)
1292 void Host_Tell_f(void)
1294 const char *playername_start = NULL;
1295 size_t playername_length = 0;
1296 int playernumber = 0;
1299 const char *p1, *p2;
1300 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1301 qboolean fromServer = false;
1303 if (cmd_source == src_command)
1305 if (cls.state == ca_dedicated)
1309 Cmd_ForwardToServer ();
1314 if (Cmd_Argc () < 2)
1317 // note this uses the chat prefix \001
1319 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1320 else if(*(sv_adminnick.string))
1321 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1323 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1326 p2 = p1 + strlen(p1);
1327 // remove the target name
1328 while (p1 < p2 && *p1 == ' ')
1333 while (p1 < p2 && *p1 == ' ')
1335 while (p1 < p2 && isdigit(*p1))
1337 playernumber = playernumber * 10 + (*p1 - '0');
1345 playername_start = p1;
1346 while (p1 < p2 && *p1 != '"')
1348 playername_length = p1 - playername_start;
1354 playername_start = p1;
1355 while (p1 < p2 && *p1 != ' ')
1357 playername_length = p1 - playername_start;
1359 while (p1 < p2 && *p1 == ' ')
1361 if(playername_start)
1363 // set playernumber to the right client
1365 if(playername_length >= sizeof(namebuf))
1368 Con_Print("Host_Tell: too long player name/ID\n");
1370 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1373 memcpy(namebuf, playername_start, playername_length);
1374 namebuf[playername_length] = 0;
1375 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1377 if (!svs.clients[playernumber].active)
1379 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1383 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1386 Con_Print("Host_Tell: invalid player name/ID\n");
1388 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1391 // remove trailing newlines
1392 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1394 // remove quotes if present
1400 else if (fromServer)
1401 Con_Print("Host_Tell: missing end quote\n");
1403 SV_ClientPrint("Host_Tell: missing end quote\n");
1405 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1408 return; // empty say
1409 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1415 host_client = svs.clients + playernumber;
1416 SV_ClientPrint(text);
1426 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1427 void Host_Color(int changetop, int changebottom)
1429 int top, bottom, playercolor;
1431 // get top and bottom either from the provided values or the current values
1432 // (allows changing only top or bottom, or both at once)
1433 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1434 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1438 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1444 playercolor = top*16 + bottom;
1446 if (cmd_source == src_command)
1448 Cvar_SetValueQuick(&cl_color, playercolor);
1452 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1455 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1457 Con_DPrint("Calling SV_ChangeTeam\n");
1458 prog->globals.server->time = sv.time;
1459 prog->globals.generic[OFS_PARM0] = playercolor;
1460 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1461 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1466 if (host_client->edict)
1468 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1469 val->_float = playercolor;
1470 host_client->edict->fields.server->team = bottom + 1;
1472 host_client->colors = playercolor;
1473 if (host_client->old_colors != host_client->colors)
1475 host_client->old_colors = host_client->colors;
1476 // send notification to all clients
1477 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1478 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1479 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1484 void Host_Color_f(void)
1488 if (Cmd_Argc() == 1)
1490 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1491 Con_Print("color <0-15> [0-15]\n");
1495 if (Cmd_Argc() == 2)
1496 top = bottom = atoi(Cmd_Argv(1));
1499 top = atoi(Cmd_Argv(1));
1500 bottom = atoi(Cmd_Argv(2));
1502 Host_Color(top, bottom);
1505 void Host_TopColor_f(void)
1507 if (Cmd_Argc() == 1)
1509 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1510 Con_Print("topcolor <0-15>\n");
1514 Host_Color(atoi(Cmd_Argv(1)), -1);
1517 void Host_BottomColor_f(void)
1519 if (Cmd_Argc() == 1)
1521 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1522 Con_Print("bottomcolor <0-15>\n");
1526 Host_Color(-1, atoi(Cmd_Argv(1)));
1529 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1530 void Host_Rate_f(void)
1534 if (Cmd_Argc() != 2)
1536 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1537 Con_Print("rate <bytespersecond>\n");
1541 rate = atoi(Cmd_Argv(1));
1543 if (cmd_source == src_command)
1545 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1549 host_client->rate = rate;
1557 void Host_Kill_f (void)
1559 if (host_client->edict->fields.server->health <= 0)
1561 SV_ClientPrint("Can't suicide -- already dead!\n");
1565 prog->globals.server->time = sv.time;
1566 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1567 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1576 void Host_Pause_f (void)
1578 if (!pausable.integer)
1579 SV_ClientPrint("Pause not allowed.\n");
1583 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1584 // send notification to all clients
1585 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1586 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1591 ======================
1593 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1594 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1595 ======================
1597 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)"};
1598 static void Host_PModel_f (void)
1603 if (Cmd_Argc () == 1)
1605 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1608 i = atoi(Cmd_Argv(1));
1610 if (cmd_source == src_command)
1612 if (cl_pmodel.integer == i)
1614 Cvar_SetValue ("_cl_pmodel", i);
1615 if (cls.state == ca_connected)
1616 Cmd_ForwardToServer ();
1620 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1624 //===========================================================================
1632 void Host_PreSpawn_f (void)
1634 if (host_client->spawned)
1636 Con_Print("prespawn not valid -- already spawned\n");
1640 if (host_client->netconnection)
1642 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1643 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1644 MSG_WriteByte (&host_client->netconnection->message, 2);
1645 host_client->sendsignon = 0; // enable unlimited sends again
1648 // reset the name change timer because the client will send name soon
1649 host_client->nametime = 0;
1657 void Host_Spawn_f (void)
1661 int stats[MAX_CL_STATS];
1663 if (host_client->spawned)
1665 Con_Print("Spawn not valid -- already spawned\n");
1669 // reset name change timer again because they might want to change name
1670 // again in the first 5 seconds after connecting
1671 host_client->nametime = 0;
1673 // LordHavoc: moved this above the QC calls at FrikaC's request
1674 // LordHavoc: commented this out
1675 //if (host_client->netconnection)
1676 // SZ_Clear (&host_client->netconnection->message);
1678 // run the entrance script
1681 // loaded games are fully initialized already
1682 if (prog->funcoffsets.RestoreGame)
1684 Con_DPrint("Calling RestoreGame\n");
1685 prog->globals.server->time = sv.time;
1686 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1687 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1692 //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);
1694 // copy spawn parms out of the client_t
1695 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1696 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1698 // call the spawn function
1699 host_client->clientconnectcalled = true;
1700 prog->globals.server->time = sv.time;
1701 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1702 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1704 if (cls.state == ca_dedicated)
1705 Con_Printf("%s connected\n", host_client->name);
1707 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1710 if (!host_client->netconnection)
1713 // send time of update
1714 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1715 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1717 // send all current names, colors, and frag counts
1718 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1720 if (!client->active)
1722 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1723 MSG_WriteByte (&host_client->netconnection->message, i);
1724 MSG_WriteString (&host_client->netconnection->message, client->name);
1725 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1726 MSG_WriteByte (&host_client->netconnection->message, i);
1727 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1728 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1729 MSG_WriteByte (&host_client->netconnection->message, i);
1730 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1733 // send all current light styles
1734 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1736 if (sv.lightstyles[i][0])
1738 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1739 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1740 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1745 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1746 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1747 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1749 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1750 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1751 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1753 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1754 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1755 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1757 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1758 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1759 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1762 // Never send a roll angle, because savegames can catch the server
1763 // in a state where it is expecting the client to correct the angle
1764 // and it won't happen if the game was just loaded, so you wind up
1765 // with a permanent head tilt
1768 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1769 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1770 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1771 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1775 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1776 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1777 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1778 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1781 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1783 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1784 MSG_WriteByte (&host_client->netconnection->message, 3);
1792 void Host_Begin_f (void)
1794 host_client->spawned = true;
1796 // LordHavoc: note: this code also exists in SV_DropClient
1800 for (i = 0;i < svs.maxclients;i++)
1801 if (svs.clients[i].active && !svs.clients[i].spawned)
1803 if (i == svs.maxclients)
1805 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1806 sv.paused = sv.loadgame = false; // we're basically done with loading now
1811 //===========================================================================
1818 Kicks a user off of the server
1821 void Host_Kick_f (void)
1824 const char *message = NULL;
1827 qboolean byNumber = false;
1835 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1837 i = (int)(atof(Cmd_Argv(2)) - 1);
1838 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1844 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1846 if (!host_client->active)
1848 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1853 if (i < svs.maxclients)
1855 if (cmd_source == src_command)
1857 if (cls.state == ca_dedicated)
1860 who = cl_name.string;
1865 // can't kick yourself!
1866 if (host_client == save)
1871 message = Cmd_Args();
1872 COM_ParseToken_Simple(&message, false, false);
1875 message++; // skip the #
1876 while (*message == ' ') // skip white space
1878 message += strlen(Cmd_Argv(2)); // skip the number
1880 while (*message && *message == ' ')
1884 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1886 SV_ClientPrintf("Kicked by %s\n", who);
1887 SV_DropClient (false); // kicked
1895 ===============================================================================
1899 ===============================================================================
1907 void Host_Give_f (void)
1915 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1920 v = atoi (Cmd_Argv(2));
1934 // MED 01/04/97 added hipnotic give stuff
1935 if (gamemode == GAME_HIPNOTIC)
1940 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1942 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1944 else if (t[0] == '9')
1945 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1946 else if (t[0] == '0')
1947 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1948 else if (t[0] >= '2')
1949 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1954 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1959 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1962 host_client->edict->fields.server->ammo_shells = v;
1965 if (gamemode == GAME_ROGUE)
1967 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1970 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1971 host_client->edict->fields.server->ammo_nails = v;
1976 host_client->edict->fields.server->ammo_nails = v;
1980 if (gamemode == GAME_ROGUE)
1982 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1986 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1987 host_client->edict->fields.server->ammo_nails = v;
1992 if (gamemode == GAME_ROGUE)
1994 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
1998 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1999 host_client->edict->fields.server->ammo_rockets = v;
2004 host_client->edict->fields.server->ammo_rockets = v;
2008 if (gamemode == GAME_ROGUE)
2010 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2014 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2015 host_client->edict->fields.server->ammo_rockets = v;
2020 host_client->edict->fields.server->health = v;
2023 if (gamemode == GAME_ROGUE)
2025 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2029 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2030 host_client->edict->fields.server->ammo_cells = v;
2035 host_client->edict->fields.server->ammo_cells = v;
2039 if (gamemode == GAME_ROGUE)
2041 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2045 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2046 host_client->edict->fields.server->ammo_cells = v;
2053 prvm_edict_t *FindViewthing (void)
2058 for (i=0 ; i<prog->num_edicts ; i++)
2060 e = PRVM_EDICT_NUM(i);
2061 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2064 Con_Print("No viewthing on map\n");
2073 void Host_Viewmodel_f (void)
2082 e = FindViewthing ();
2087 m = Mod_ForName (Cmd_Argv(1), false, true, false);
2088 if (!m || !m->loaded || !m->Draw)
2090 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2094 e->fields.server->frame = 0;
2095 cl.model_precache[(int)e->fields.server->modelindex] = m;
2103 void Host_Viewframe_f (void)
2113 e = FindViewthing ();
2117 m = cl.model_precache[(int)e->fields.server->modelindex];
2119 f = atoi(Cmd_Argv(1));
2120 if (f >= m->numframes)
2123 e->fields.server->frame = f;
2127 void PrintFrameName (dp_model_t *m, int frame)
2130 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2132 Con_Printf("frame %i\n", frame);
2140 void Host_Viewnext_f (void)
2149 e = FindViewthing ();
2153 m = cl.model_precache[(int)e->fields.server->modelindex];
2155 e->fields.server->frame = e->fields.server->frame + 1;
2156 if (e->fields.server->frame >= m->numframes)
2157 e->fields.server->frame = m->numframes - 1;
2159 PrintFrameName (m, (int)e->fields.server->frame);
2167 void Host_Viewprev_f (void)
2176 e = FindViewthing ();
2181 m = cl.model_precache[(int)e->fields.server->modelindex];
2183 e->fields.server->frame = e->fields.server->frame - 1;
2184 if (e->fields.server->frame < 0)
2185 e->fields.server->frame = 0;
2187 PrintFrameName (m, (int)e->fields.server->frame);
2191 ===============================================================================
2195 ===============================================================================
2204 void Host_Startdemos_f (void)
2208 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2214 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2217 Con_DPrintf("%i demo(s) in loop\n", c);
2219 for (i=1 ; i<c+1 ; i++)
2220 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2222 // LordHavoc: clear the remaining slots
2223 for (;i <= MAX_DEMOS;i++)
2224 cls.demos[i-1][0] = 0;
2226 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2240 Return to looping demos
2243 void Host_Demos_f (void)
2245 if (cls.state == ca_dedicated)
2247 if (cls.demonum == -1)
2257 Return to looping demos
2260 void Host_Stopdemo_f (void)
2262 if (!cls.demoplayback)
2265 Host_ShutdownServer ();
2268 void Host_SendCvar_f (void)
2272 const char *cvarname;
2277 cvarname = Cmd_Argv(1);
2278 if (cls.state == ca_connected)
2280 c = Cvar_FindVar(cvarname);
2281 // LordHavoc: if there is no such cvar or if it is private, send a
2282 // reply indicating that it has no value
2283 if(!c || (c->flags & CVAR_PRIVATE))
2284 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2286 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2289 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2293 if (cls.state != ca_dedicated)
2297 for(;i<svs.maxclients;i++)
2298 if(svs.clients[i].active && svs.clients[i].netconnection)
2300 host_client = &svs.clients[i];
2301 Host_ClientCommands("sendcvar %s\n", cvarname);
2306 static void MaxPlayers_f(void)
2310 if (Cmd_Argc() != 2)
2312 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
2318 Con_Print("maxplayers can not be changed while a server is running.\n");
2319 Con_Print("It will be changed on next server startup (\"map\" command).\n");
2322 n = atoi(Cmd_Argv(1));
2323 n = bound(1, n, MAX_SCOREBOARD);
2324 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2326 svs.maxclients_next = n;
2328 Cvar_Set ("deathmatch", "0");
2330 Cvar_Set ("deathmatch", "1");
2333 //=============================================================================
2335 // QuakeWorld commands
2338 =====================
2341 Send the rest of the command line over as
2342 an unconnected command.
2343 =====================
2345 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2349 lhnetsocket_t *mysocket;
2351 if (!rcon_password.string || !rcon_password.string[0])
2353 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2357 for (i = 0;rcon_password.string[i];i++)
2359 if (ISWHITESPACE(rcon_password.string[i]))
2361 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2367 to = cls.netcon->peeraddress;
2370 if (!rcon_address.string[0])
2372 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2375 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2377 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2380 // simply put together the rcon packet and send it
2381 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2386 ====================
2389 user <name or userid>
2391 Dump userdata / masterdata for a user
2392 ====================
2394 void Host_User_f (void) // credit: taken from QuakeWorld
2399 if (Cmd_Argc() != 2)
2401 Con_Printf ("Usage: user <username / userid>\n");
2405 uid = atoi(Cmd_Argv(1));
2407 for (i = 0;i < cl.maxclients;i++)
2409 if (!cl.scores[i].name[0])
2411 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2413 InfoString_Print(cl.scores[i].qw_userinfo);
2417 Con_Printf ("User not in server.\n");
2421 ====================
2424 Dump userids for all current players
2425 ====================
2427 void Host_Users_f (void) // credit: taken from QuakeWorld
2433 Con_Printf ("userid frags name\n");
2434 Con_Printf ("------ ----- ----\n");
2435 for (i = 0;i < cl.maxclients;i++)
2437 if (cl.scores[i].name[0])
2439 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2444 Con_Printf ("%i total users\n", c);
2449 Host_FullServerinfo_f
2451 Sent by server when serverinfo changes
2454 // TODO: shouldn't this be a cvar instead?
2455 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2458 if (Cmd_Argc() != 2)
2460 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2464 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2465 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2466 cl.qw_teamplay = atoi(temp);
2473 Allow clients to change userinfo
2477 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2484 if (Cmd_Argc() != 2)
2486 Con_Printf ("fullinfo <complete info string>\n");
2496 while (*s && *s != '\\')
2502 Con_Printf ("MISSING VALUE\n");
2508 while (*s && *s != '\\')
2515 CL_SetInfo(key, value, false, false, false, false);
2523 Allow clients to change userinfo
2526 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2528 if (Cmd_Argc() == 1)
2530 InfoString_Print(cls.userinfo);
2533 if (Cmd_Argc() != 3)
2535 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2538 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2542 ====================
2545 packet <destination> <contents>
2547 Contents allows \n escape character
2548 ====================
2550 void Host_Packet_f (void) // credit: taken from QuakeWorld
2556 lhnetaddress_t address;
2557 lhnetsocket_t *mysocket;
2559 if (Cmd_Argc() != 3)
2561 Con_Printf ("packet <destination> <contents>\n");
2565 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2567 Con_Printf ("Bad address\n");
2573 send[0] = send[1] = send[2] = send[3] = 0xff;
2575 l = (int)strlen (in);
2576 for (i=0 ; i<l ; i++)
2578 if (out >= send + sizeof(send) - 1)
2580 if (in[i] == '\\' && in[i+1] == 'n')
2585 else if (in[i] == '\\' && in[i+1] == '0')
2590 else if (in[i] == '\\' && in[i+1] == 't')
2595 else if (in[i] == '\\' && in[i+1] == 'r')
2600 else if (in[i] == '\\' && in[i+1] == '"')
2609 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2611 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2613 NetConn_Write(mysocket, send, out - send, &address);
2617 ====================
2620 Send back ping and packet loss update for all current players to this player
2621 ====================
2623 void Host_Pings_f (void)
2625 int i, j, ping, packetloss;
2628 if (!host_client->netconnection)
2631 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2633 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2634 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2636 for (i = 0;i < svs.maxclients;i++)
2639 if (svs.clients[i].netconnection)
2640 for (j = 0;j < NETGRAPH_PACKETS;j++)
2641 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2643 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2644 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2645 ping = bound(0, ping, 9999);
2646 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2648 // send qw_svc_updateping and qw_svc_updatepl messages
2649 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2650 MSG_WriteShort(&host_client->netconnection->message, ping);
2651 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2652 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2656 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2657 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2658 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2661 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2662 MSG_WriteString(&host_client->netconnection->message, "\n");
2665 void Host_PingPLReport_f(void)
2669 if (l > cl.maxclients)
2671 for (i = 0;i < l;i++)
2673 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2674 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2678 //=============================================================================
2685 void Host_InitCommands (void)
2687 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2689 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2690 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2691 if (gamemode == GAME_NEHAHRA)
2693 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2694 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2695 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2696 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2697 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2701 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2702 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2703 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2704 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2705 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2707 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2708 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2709 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2710 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2711 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)");
2712 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2713 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2714 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2715 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2716 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2717 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2718 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2719 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2720 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2721 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2723 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2724 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2725 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2727 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2728 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2729 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2730 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2732 Cvar_RegisterVariable (&cl_name);
2733 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2734 Cvar_RegisterVariable (&cl_color);
2735 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2736 Cvar_RegisterVariable (&cl_rate);
2737 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2738 if (gamemode == GAME_NEHAHRA)
2740 Cvar_RegisterVariable (&cl_pmodel);
2741 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2744 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2745 Cvar_RegisterVariable (&cl_playermodel);
2746 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2747 Cvar_RegisterVariable (&cl_playerskin);
2748 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2750 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2751 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2752 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)");
2753 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2755 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2757 Cvar_RegisterVariable (&rcon_password);
2758 Cvar_RegisterVariable (&rcon_address);
2759 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)");
2760 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2761 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2762 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2763 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2764 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2765 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2766 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2767 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2769 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)");
2770 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)");
2772 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)");
2773 Cvar_RegisterVariable (&r_fixtrans_auto);
2775 Cvar_RegisterVariable (&team);
2776 Cvar_RegisterVariable (&skin);
2777 Cvar_RegisterVariable (&noaim);
2779 Cvar_RegisterVariable(&sv_cheats);
2780 Cvar_RegisterVariable(&sv_adminnick);
2781 Cvar_RegisterVariable(&sv_status_privacy);
2782 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2785 void Host_NoOperation_f(void)