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();
369 svs.serverflags = 0; // haven't completed an episode yet
370 allowcheats = sv_cheats.integer != 0;
371 strlcpy(level, Cmd_Argv(1), sizeof(level));
372 SV_SpawnServer(level);
373 if (sv.active && cls.state == ca_disconnected)
374 CL_EstablishConnection("local:1");
381 Goes to a new map, taking all clients along
384 void Host_Changelevel_f (void)
386 char level[MAX_QPATH];
390 Con_Print("changelevel <levelname> : continue game on a new level\n");
403 SV_SaveSpawnparms ();
405 allowcheats = sv_cheats.integer != 0;
406 strlcpy(level, Cmd_Argv(1), sizeof(level));
407 SV_SpawnServer(level);
408 if (sv.active && cls.state == ca_disconnected)
409 CL_EstablishConnection("local:1");
416 Restarts the current server for a dead player
419 void Host_Restart_f (void)
421 char mapname[MAX_QPATH];
425 Con_Print("restart : restart current level\n");
430 Con_Print("Only the server may restart\n");
437 allowcheats = sv_cheats.integer != 0;
438 strlcpy(mapname, sv.name, sizeof(mapname));
439 SV_SpawnServer(mapname);
440 if (sv.active && cls.state == ca_disconnected)
441 CL_EstablishConnection("local:1");
448 This command causes the client to wait for the signon messages again.
449 This is sent just before a server changes levels
452 void Host_Reconnect_f (void)
455 // if not connected, reconnect to the most recent server
458 // if we have connected to a server recently, the userinfo
459 // will still contain its IP address, so get the address...
460 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
462 CL_EstablishConnection(temp);
464 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
467 // if connected, do something based on protocol
468 if (cls.protocol == PROTOCOL_QUAKEWORLD)
470 // quakeworld can just re-login
471 if (cls.qw_downloadmemory) // don't change when downloading
476 if (cls.state == ca_connected && cls.signon < SIGNONS)
478 Con_Printf("reconnecting...\n");
479 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
480 MSG_WriteString(&cls.netcon->message, "new");
485 // netquake uses reconnect on level changes (silly)
488 Con_Print("reconnect : wait for signon messages again\n");
493 Con_Print("reconnect: no signon, ignoring reconnect\n");
496 cls.signon = 0; // need new connection messages
501 =====================
504 User command to connect to server
505 =====================
507 void Host_Connect_f (void)
511 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
514 CL_EstablishConnection(Cmd_Argv(1));
519 ===============================================================================
523 ===============================================================================
526 #define SAVEGAME_VERSION 5
528 void Host_Savegame_to (const char *name)
531 int i, lightstyles = 64;
532 char comment[SAVEGAME_COMMENT_LENGTH+1];
535 // first we have to figure out if this can be saved in 64 lightstyles
536 // (for Quake compatibility)
537 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
538 if (sv.lightstyles[i][0])
541 isserver = !strcmp(PRVM_NAME, "server");
543 Con_Printf("Saving game to %s...\n", name);
544 f = FS_OpenRealFile(name, "wb", false);
547 Con_Print("ERROR: couldn't open.\n");
551 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
553 memset(comment, 0, sizeof(comment));
555 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);
557 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
558 // convert space to _ to make stdio happy
559 // LordHavoc: convert control characters to _ as well
560 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
561 if (ISWHITESPACEORCONTROL(comment[i]))
563 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
565 FS_Printf(f, "%s\n", comment);
568 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
569 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
570 FS_Printf(f, "%d\n", current_skill);
571 FS_Printf(f, "%s\n", sv.name);
572 FS_Printf(f, "%f\n",sv.time);
576 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
577 FS_Printf(f, "(dummy)\n");
578 FS_Printf(f, "%d\n", 0);
579 FS_Printf(f, "%s\n", "(dummy)");
580 FS_Printf(f, "%f\n", realtime);
583 // write the light styles
584 for (i=0 ; i<lightstyles ; i++)
586 if (isserver && sv.lightstyles[i][0])
587 FS_Printf(f, "%s\n", sv.lightstyles[i]);
592 PRVM_ED_WriteGlobals (f);
593 for (i=0 ; i<prog->num_edicts ; i++)
595 FS_Printf(f,"// edict %d\n", i);
596 //Con_Printf("edict %d...\n", i);
597 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
602 FS_Printf(f,"// DarkPlaces extended savegame\n");
603 // darkplaces extension - extra lightstyles, support for color lightstyles
604 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
605 if (isserver && sv.lightstyles[i][0])
606 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
608 // darkplaces extension - model precaches
609 for (i=1 ; i<MAX_MODELS ; i++)
610 if (sv.model_precache[i][0])
611 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
613 // darkplaces extension - sound precaches
614 for (i=1 ; i<MAX_SOUNDS ; i++)
615 if (sv.sound_precache[i][0])
616 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
621 Con_Print("done.\n");
629 void Host_Savegame_f (void)
631 char name[MAX_QPATH];
635 Con_Print("Can't save - no server running.\n");
641 // singleplayer checks
644 Con_Print("Can't save in intermission.\n");
648 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
650 Con_Print("Can't savegame with a dead player\n");
655 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");
659 Con_Print("save <savename> : save a game\n");
663 if (strstr(Cmd_Argv(1), ".."))
665 Con_Print("Relative pathnames are not allowed.\n");
669 strlcpy (name, Cmd_Argv(1), sizeof (name));
670 FS_DefaultExtension (name, ".sav", sizeof (name));
673 Host_Savegame_to(name);
683 void Host_Loadgame_f (void)
685 char filename[MAX_QPATH];
686 char mapname[MAX_QPATH];
696 float spawn_parms[NUM_SPAWN_PARMS];
700 Con_Print("load <savename> : load a game\n");
704 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
705 FS_DefaultExtension (filename, ".sav", sizeof (filename));
707 Con_Printf("Loading game from %s...\n", filename);
709 // stop playing demos
710 if (cls.demoplayback)
716 cls.demonum = -1; // stop demo loop in case this fails
718 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
721 Con_Print("ERROR: couldn't open.\n");
725 if(developer_entityparsing.integer)
726 Con_Printf("Host_Loadgame_f: loading version\n");
729 COM_ParseToken_Simple(&t, false, false);
730 version = atoi(com_token);
731 if (version != SAVEGAME_VERSION)
734 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
738 if(developer_entityparsing.integer)
739 Con_Printf("Host_Loadgame_f: loading description\n");
742 COM_ParseToken_Simple(&t, false, false);
744 for (i = 0;i < NUM_SPAWN_PARMS;i++)
746 COM_ParseToken_Simple(&t, false, false);
747 spawn_parms[i] = atof(com_token);
750 COM_ParseToken_Simple(&t, false, false);
751 // this silliness is so we can load 1.06 save files, which have float skill values
752 current_skill = (int)(atof(com_token) + 0.5);
753 Cvar_SetValue ("skill", (float)current_skill);
755 if(developer_entityparsing.integer)
756 Con_Printf("Host_Loadgame_f: loading mapname\n");
759 COM_ParseToken_Simple(&t, false, false);
760 strlcpy (mapname, com_token, sizeof(mapname));
762 if(developer_entityparsing.integer)
763 Con_Printf("Host_Loadgame_f: loading time\n");
766 COM_ParseToken_Simple(&t, false, false);
767 time = atof(com_token);
769 allowcheats = sv_cheats.integer != 0;
771 if(developer_entityparsing.integer)
772 Con_Printf("Host_Loadgame_f: spawning server\n");
774 SV_SpawnServer (mapname);
778 Con_Print("Couldn't load map\n");
781 sv.paused = true; // pause until all clients connect
784 if(developer_entityparsing.integer)
785 Con_Printf("Host_Loadgame_f: loading light styles\n");
787 // load the light styles
793 for (i = 0;i < MAX_LIGHTSTYLES;i++)
797 COM_ParseToken_Simple(&t, false, false);
798 // if this is a 64 lightstyle savegame produced by Quake, stop now
799 // we have to check this because darkplaces may save more than 64
800 if (com_token[0] == '{')
805 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
808 if(developer_entityparsing.integer)
809 Con_Printf("Host_Loadgame_f: skipping until globals\n");
811 // now skip everything before the first opening brace
812 // (this is for forward compatibility, so that older versions (at
813 // least ones with this fix) can load savegames with extra data before the
814 // first brace, as might be produced by a later engine version)
818 if (!COM_ParseToken_Simple(&t, false, false))
820 if (com_token[0] == '{')
827 // load the edicts out of the savegame file
832 while (COM_ParseToken_Simple(&t, false, false))
833 if (!strcmp(com_token, "}"))
835 if (!COM_ParseToken_Simple(&start, false, false))
840 if (strcmp(com_token,"{"))
843 Host_Error ("First token isn't a brace");
848 if(developer_entityparsing.integer)
849 Con_Printf("Host_Loadgame_f: loading globals\n");
851 // parse the global vars
852 PRVM_ED_ParseGlobals (start);
857 if (entnum >= MAX_EDICTS)
860 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
862 while (entnum >= prog->max_edicts)
863 PRVM_MEM_IncreaseEdicts();
864 ent = PRVM_EDICT_NUM(entnum);
865 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
866 ent->priv.server->free = false;
868 if(developer_entityparsing.integer)
869 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
871 PRVM_ED_ParseEdict (start, ent);
873 // link it into the bsp tree
874 if (!ent->priv.server->free)
875 SV_LinkEdict (ent, false);
882 prog->num_edicts = entnum;
885 for (i = 0;i < NUM_SPAWN_PARMS;i++)
886 svs.clients[0].spawn_parms[i] = spawn_parms[i];
888 if(developer_entityparsing.integer)
889 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
891 // read extended data if present
892 // the extended data is stored inside a /* */ comment block, which the
893 // parser intentionally skips, so we have to check for it manually here
896 while (*end == '\r' || *end == '\n')
898 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
900 if(developer_entityparsing.integer)
901 Con_Printf("Host_Loadgame_f: loading extended data\n");
903 Con_Printf("Loading extended DarkPlaces savegame\n");
905 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
906 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
907 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
908 while (COM_ParseToken_Simple(&t, false, false))
910 if (!strcmp(com_token, "sv.lightstyles"))
912 COM_ParseToken_Simple(&t, false, false);
914 COM_ParseToken_Simple(&t, false, false);
915 if (i >= 0 && i < MAX_LIGHTSTYLES)
916 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
918 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
920 else if (!strcmp(com_token, "sv.model_precache"))
922 COM_ParseToken_Simple(&t, false, false);
924 COM_ParseToken_Simple(&t, false, false);
925 if (i >= 0 && i < MAX_MODELS)
927 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
928 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
931 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
933 else if (!strcmp(com_token, "sv.sound_precache"))
935 COM_ParseToken_Simple(&t, false, false);
937 COM_ParseToken_Simple(&t, false, false);
938 if (i >= 0 && i < MAX_SOUNDS)
939 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
941 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
943 // skip any trailing text or unrecognized commands
944 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
951 if(developer_entityparsing.integer)
952 Con_Printf("Host_Loadgame_f: finished\n");
956 // make sure we're connected to loopback
957 if (sv.active && cls.state == ca_disconnected)
958 CL_EstablishConnection("local:1");
961 //============================================================================
964 ======================
966 ======================
968 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
969 void Host_Name_f (void)
972 qboolean valid_colors;
973 char newName[sizeof(host_client->name)];
975 if (Cmd_Argc () == 1)
977 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
981 if (Cmd_Argc () == 2)
982 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
984 strlcpy (newName, Cmd_Args(), sizeof (newName));
986 if (cmd_source == src_command)
988 Cvar_Set ("_cl_name", newName);
992 if (realtime < host_client->nametime)
994 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
998 host_client->nametime = realtime + 5;
1000 // point the string back at updateclient->name to keep it safe
1001 strlcpy (host_client->name, newName, sizeof (host_client->name));
1003 for (i = 0, j = 0;host_client->name[i];i++)
1004 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1005 host_client->name[j++] = host_client->name[i];
1006 host_client->name[j] = 0;
1008 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1009 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1011 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1012 host_client->name[sizeof(host_client->name) - 1] = 0;
1013 host_client->name[0] = STRING_COLOR_TAG;
1014 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1017 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1018 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1021 l = strlen(host_client->name);
1022 if(l < sizeof(host_client->name) - 1)
1024 // duplicate the color tag to escape it
1025 host_client->name[i] = STRING_COLOR_TAG;
1026 host_client->name[i+1] = 0;
1027 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1031 // remove the last character to fix the color code
1032 host_client->name[l-1] = 0;
1033 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1037 // find the last color tag offset and decide if we need to add a reset tag
1038 for (i = 0, j = -1;host_client->name[i];i++)
1040 if (host_client->name[i] == STRING_COLOR_TAG)
1042 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1045 // if this happens to be a reset tag then we don't need one
1046 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1051 if (host_client->name[i+1] == STRING_COLOR_RGB_DEFAULT && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4]))
1057 if (host_client->name[i+1] == STRING_COLOR_TAG)
1064 // does not end in the default color string, so add it
1065 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1066 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1068 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1069 if (strcmp(host_client->old_name, host_client->name))
1071 if (host_client->spawned)
1072 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1073 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1074 // send notification to all clients
1075 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1076 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1077 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1078 SV_WriteNetnameIntoDemo(host_client);
1083 ======================
1085 ======================
1087 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1088 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1089 void Host_Playermodel_f (void)
1092 char newPath[sizeof(host_client->playermodel)];
1094 if (Cmd_Argc () == 1)
1096 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1100 if (Cmd_Argc () == 2)
1101 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1103 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1105 for (i = 0, j = 0;newPath[i];i++)
1106 if (newPath[i] != '\r' && newPath[i] != '\n')
1107 newPath[j++] = newPath[i];
1110 if (cmd_source == src_command)
1112 Cvar_Set ("_cl_playermodel", newPath);
1117 if (realtime < host_client->nametime)
1119 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1123 host_client->nametime = realtime + 5;
1126 // point the string back at updateclient->name to keep it safe
1127 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1128 if( prog->fieldoffsets.playermodel >= 0 )
1129 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1130 if (strcmp(host_client->old_model, host_client->playermodel))
1132 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1133 /*// send notification to all clients
1134 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1135 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1136 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1141 ======================
1143 ======================
1145 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1146 void Host_Playerskin_f (void)
1149 char newPath[sizeof(host_client->playerskin)];
1151 if (Cmd_Argc () == 1)
1153 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1157 if (Cmd_Argc () == 2)
1158 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1160 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1162 for (i = 0, j = 0;newPath[i];i++)
1163 if (newPath[i] != '\r' && newPath[i] != '\n')
1164 newPath[j++] = newPath[i];
1167 if (cmd_source == src_command)
1169 Cvar_Set ("_cl_playerskin", newPath);
1174 if (realtime < host_client->nametime)
1176 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1180 host_client->nametime = realtime + 5;
1183 // point the string back at updateclient->name to keep it safe
1184 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1185 if( prog->fieldoffsets.playerskin >= 0 )
1186 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1187 if (strcmp(host_client->old_skin, host_client->playerskin))
1189 //if (host_client->spawned)
1190 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1191 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1192 /*// send notification to all clients
1193 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1194 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1195 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1199 void Host_Version_f (void)
1201 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1204 void Host_Say(qboolean teamonly)
1210 // LordHavoc: long say messages
1212 qboolean fromServer = false;
1214 if (cmd_source == src_command)
1216 if (cls.state == ca_dedicated)
1223 Cmd_ForwardToServer ();
1228 if (Cmd_Argc () < 2)
1231 if (!teamplay.integer)
1241 // note this uses the chat prefix \001
1242 if (!fromServer && !teamonly)
1243 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1244 else if (!fromServer && teamonly)
1245 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1246 else if(*(sv_adminnick.string))
1247 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1249 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1250 p2 = text + strlen(text);
1251 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1253 if (p2[-1] == '\"' && quoted)
1258 strlcat(text, "\n", sizeof(text));
1260 // note: save is not a valid edict if fromServer is true
1262 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1263 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1264 SV_ClientPrint(text);
1267 if (cls.state == ca_dedicated)
1268 Con_Print(&text[1]);
1272 void Host_Say_f(void)
1278 void Host_Say_Team_f(void)
1284 void Host_Tell_f(void)
1286 const char *playername_start = NULL;
1287 size_t playername_length = 0;
1288 int playernumber = 0;
1291 const char *p1, *p2;
1292 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1293 qboolean fromServer = false;
1295 if (cmd_source == src_command)
1297 if (cls.state == ca_dedicated)
1301 Cmd_ForwardToServer ();
1306 if (Cmd_Argc () < 2)
1309 // note this uses the chat prefix \001
1311 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1312 else if(*(sv_adminnick.string))
1313 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1315 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1318 p2 = p1 + strlen(p1);
1319 // remove the target name
1320 while (p1 < p2 && *p1 == ' ')
1325 while (p1 < p2 && *p1 == ' ')
1327 while (p1 < p2 && isdigit(*p1))
1329 playernumber = playernumber * 10 + (*p1 - '0');
1337 playername_start = p1;
1338 while (p1 < p2 && *p1 != '"')
1340 playername_length = p1 - playername_start;
1346 playername_start = p1;
1347 while (p1 < p2 && *p1 != ' ')
1349 playername_length = p1 - playername_start;
1351 while (p1 < p2 && *p1 == ' ')
1353 if(playername_start)
1355 // set playernumber to the right client
1357 if(playername_length >= sizeof(namebuf))
1360 Con_Print("Host_Tell: too long player name/ID\n");
1362 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1365 memcpy(namebuf, playername_start, playername_length);
1366 namebuf[playername_length] = 0;
1367 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1369 if (!svs.clients[playernumber].active)
1371 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1375 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1378 Con_Print("Host_Tell: invalid player name/ID\n");
1380 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1383 // remove trailing newlines
1384 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1386 // remove quotes if present
1392 else if (fromServer)
1393 Con_Print("Host_Tell: missing end quote\n");
1395 SV_ClientPrint("Host_Tell: missing end quote\n");
1397 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1400 return; // empty say
1401 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1407 host_client = svs.clients + playernumber;
1408 SV_ClientPrint(text);
1418 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1419 void Host_Color(int changetop, int changebottom)
1421 int top, bottom, playercolor;
1423 // get top and bottom either from the provided values or the current values
1424 // (allows changing only top or bottom, or both at once)
1425 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1426 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1430 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1436 playercolor = top*16 + bottom;
1438 if (cmd_source == src_command)
1440 Cvar_SetValueQuick(&cl_color, playercolor);
1444 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1447 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1449 Con_DPrint("Calling SV_ChangeTeam\n");
1450 prog->globals.server->time = sv.time;
1451 prog->globals.generic[OFS_PARM0] = playercolor;
1452 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1453 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1458 if (host_client->edict)
1460 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1461 val->_float = playercolor;
1462 host_client->edict->fields.server->team = bottom + 1;
1464 host_client->colors = playercolor;
1465 if (host_client->old_colors != host_client->colors)
1467 host_client->old_colors = host_client->colors;
1468 // send notification to all clients
1469 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1470 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1471 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1476 void Host_Color_f(void)
1480 if (Cmd_Argc() == 1)
1482 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1483 Con_Print("color <0-15> [0-15]\n");
1487 if (Cmd_Argc() == 2)
1488 top = bottom = atoi(Cmd_Argv(1));
1491 top = atoi(Cmd_Argv(1));
1492 bottom = atoi(Cmd_Argv(2));
1494 Host_Color(top, bottom);
1497 void Host_TopColor_f(void)
1499 if (Cmd_Argc() == 1)
1501 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1502 Con_Print("topcolor <0-15>\n");
1506 Host_Color(atoi(Cmd_Argv(1)), -1);
1509 void Host_BottomColor_f(void)
1511 if (Cmd_Argc() == 1)
1513 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1514 Con_Print("bottomcolor <0-15>\n");
1518 Host_Color(-1, atoi(Cmd_Argv(1)));
1521 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1522 void Host_Rate_f(void)
1526 if (Cmd_Argc() != 2)
1528 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1529 Con_Print("rate <bytespersecond>\n");
1533 rate = atoi(Cmd_Argv(1));
1535 if (cmd_source == src_command)
1537 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1541 host_client->rate = rate;
1549 void Host_Kill_f (void)
1551 if (host_client->edict->fields.server->health <= 0)
1553 SV_ClientPrint("Can't suicide -- already dead!\n");
1557 prog->globals.server->time = sv.time;
1558 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1559 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1568 void Host_Pause_f (void)
1570 if (!pausable.integer)
1571 SV_ClientPrint("Pause not allowed.\n");
1575 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1576 // send notification to all clients
1577 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1578 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1583 ======================
1585 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1586 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1587 ======================
1589 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)"};
1590 static void Host_PModel_f (void)
1595 if (Cmd_Argc () == 1)
1597 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1600 i = atoi(Cmd_Argv(1));
1602 if (cmd_source == src_command)
1604 if (cl_pmodel.integer == i)
1606 Cvar_SetValue ("_cl_pmodel", i);
1607 if (cls.state == ca_connected)
1608 Cmd_ForwardToServer ();
1612 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1616 //===========================================================================
1624 void Host_PreSpawn_f (void)
1626 if (host_client->spawned)
1628 Con_Print("prespawn not valid -- already spawned\n");
1632 if (host_client->netconnection)
1634 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1635 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1636 MSG_WriteByte (&host_client->netconnection->message, 2);
1637 host_client->sendsignon = 0; // enable unlimited sends again
1640 // reset the name change timer because the client will send name soon
1641 host_client->nametime = 0;
1649 void Host_Spawn_f (void)
1653 int stats[MAX_CL_STATS];
1655 if (host_client->spawned)
1657 Con_Print("Spawn not valid -- already spawned\n");
1661 // reset name change timer again because they might want to change name
1662 // again in the first 5 seconds after connecting
1663 host_client->nametime = 0;
1665 // LordHavoc: moved this above the QC calls at FrikaC's request
1666 // LordHavoc: commented this out
1667 //if (host_client->netconnection)
1668 // SZ_Clear (&host_client->netconnection->message);
1670 // run the entrance script
1673 // loaded games are fully initialized already
1674 if (prog->funcoffsets.RestoreGame)
1676 Con_DPrint("Calling RestoreGame\n");
1677 prog->globals.server->time = sv.time;
1678 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1679 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1684 //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);
1686 // copy spawn parms out of the client_t
1687 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1688 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1690 // call the spawn function
1691 host_client->clientconnectcalled = true;
1692 prog->globals.server->time = sv.time;
1693 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1694 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1696 if (cls.state == ca_dedicated)
1697 Con_Printf("%s connected\n", host_client->name);
1699 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1702 if (!host_client->netconnection)
1705 // send time of update
1706 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1707 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1709 // send all current names, colors, and frag counts
1710 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1712 if (!client->active)
1714 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1715 MSG_WriteByte (&host_client->netconnection->message, i);
1716 MSG_WriteString (&host_client->netconnection->message, client->name);
1717 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1718 MSG_WriteByte (&host_client->netconnection->message, i);
1719 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1720 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1721 MSG_WriteByte (&host_client->netconnection->message, i);
1722 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1725 // send all current light styles
1726 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1728 if (sv.lightstyles[i][0])
1730 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1731 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1732 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1737 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1738 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1739 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1741 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1742 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1743 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1745 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1746 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1747 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1749 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1750 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1751 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1754 // Never send a roll angle, because savegames can catch the server
1755 // in a state where it is expecting the client to correct the angle
1756 // and it won't happen if the game was just loaded, so you wind up
1757 // with a permanent head tilt
1760 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1761 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1762 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1763 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1767 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1768 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1769 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1770 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1773 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1775 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1776 MSG_WriteByte (&host_client->netconnection->message, 3);
1784 void Host_Begin_f (void)
1786 host_client->spawned = true;
1788 // LordHavoc: note: this code also exists in SV_DropClient
1792 for (i = 0;i < svs.maxclients;i++)
1793 if (svs.clients[i].active && !svs.clients[i].spawned)
1795 if (i == svs.maxclients)
1797 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1798 sv.paused = sv.loadgame = false; // we're basically done with loading now
1803 //===========================================================================
1810 Kicks a user off of the server
1813 void Host_Kick_f (void)
1816 const char *message = NULL;
1819 qboolean byNumber = false;
1827 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1829 i = (int)(atof(Cmd_Argv(2)) - 1);
1830 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1836 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1838 if (!host_client->active)
1840 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1845 if (i < svs.maxclients)
1847 if (cmd_source == src_command)
1849 if (cls.state == ca_dedicated)
1852 who = cl_name.string;
1857 // can't kick yourself!
1858 if (host_client == save)
1863 message = Cmd_Args();
1864 COM_ParseToken_Simple(&message, false, false);
1867 message++; // skip the #
1868 while (*message == ' ') // skip white space
1870 message += strlen(Cmd_Argv(2)); // skip the number
1872 while (*message && *message == ' ')
1876 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1878 SV_ClientPrintf("Kicked by %s\n", who);
1879 SV_DropClient (false); // kicked
1887 ===============================================================================
1891 ===============================================================================
1899 void Host_Give_f (void)
1907 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1912 v = atoi (Cmd_Argv(2));
1926 // MED 01/04/97 added hipnotic give stuff
1927 if (gamemode == GAME_HIPNOTIC)
1932 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1934 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1936 else if (t[0] == '9')
1937 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1938 else if (t[0] == '0')
1939 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1940 else if (t[0] >= '2')
1941 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1946 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1951 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1954 host_client->edict->fields.server->ammo_shells = v;
1957 if (gamemode == GAME_ROGUE)
1959 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1962 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1963 host_client->edict->fields.server->ammo_nails = v;
1968 host_client->edict->fields.server->ammo_nails = v;
1972 if (gamemode == GAME_ROGUE)
1974 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1978 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1979 host_client->edict->fields.server->ammo_nails = v;
1984 if (gamemode == GAME_ROGUE)
1986 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
1990 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1991 host_client->edict->fields.server->ammo_rockets = v;
1996 host_client->edict->fields.server->ammo_rockets = v;
2000 if (gamemode == GAME_ROGUE)
2002 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2006 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2007 host_client->edict->fields.server->ammo_rockets = v;
2012 host_client->edict->fields.server->health = v;
2015 if (gamemode == GAME_ROGUE)
2017 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2021 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2022 host_client->edict->fields.server->ammo_cells = v;
2027 host_client->edict->fields.server->ammo_cells = v;
2031 if (gamemode == GAME_ROGUE)
2033 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2037 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2038 host_client->edict->fields.server->ammo_cells = v;
2045 prvm_edict_t *FindViewthing (void)
2050 for (i=0 ; i<prog->num_edicts ; i++)
2052 e = PRVM_EDICT_NUM(i);
2053 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2056 Con_Print("No viewthing on map\n");
2065 void Host_Viewmodel_f (void)
2074 e = FindViewthing ();
2079 m = Mod_ForName (Cmd_Argv(1), false, true, false);
2080 if (!m || !m->loaded || !m->Draw)
2082 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2086 e->fields.server->frame = 0;
2087 cl.model_precache[(int)e->fields.server->modelindex] = m;
2095 void Host_Viewframe_f (void)
2105 e = FindViewthing ();
2109 m = cl.model_precache[(int)e->fields.server->modelindex];
2111 f = atoi(Cmd_Argv(1));
2112 if (f >= m->numframes)
2115 e->fields.server->frame = f;
2119 void PrintFrameName (dp_model_t *m, int frame)
2122 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2124 Con_Printf("frame %i\n", frame);
2132 void Host_Viewnext_f (void)
2141 e = FindViewthing ();
2145 m = cl.model_precache[(int)e->fields.server->modelindex];
2147 e->fields.server->frame = e->fields.server->frame + 1;
2148 if (e->fields.server->frame >= m->numframes)
2149 e->fields.server->frame = m->numframes - 1;
2151 PrintFrameName (m, (int)e->fields.server->frame);
2159 void Host_Viewprev_f (void)
2168 e = FindViewthing ();
2173 m = cl.model_precache[(int)e->fields.server->modelindex];
2175 e->fields.server->frame = e->fields.server->frame - 1;
2176 if (e->fields.server->frame < 0)
2177 e->fields.server->frame = 0;
2179 PrintFrameName (m, (int)e->fields.server->frame);
2183 ===============================================================================
2187 ===============================================================================
2196 void Host_Startdemos_f (void)
2200 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2206 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2209 Con_DPrintf("%i demo(s) in loop\n", c);
2211 for (i=1 ; i<c+1 ; i++)
2212 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2214 // LordHavoc: clear the remaining slots
2215 for (;i <= MAX_DEMOS;i++)
2216 cls.demos[i-1][0] = 0;
2218 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2232 Return to looping demos
2235 void Host_Demos_f (void)
2237 if (cls.state == ca_dedicated)
2239 if (cls.demonum == -1)
2249 Return to looping demos
2252 void Host_Stopdemo_f (void)
2254 if (!cls.demoplayback)
2257 Host_ShutdownServer ();
2260 void Host_SendCvar_f (void)
2264 const char *cvarname;
2269 cvarname = Cmd_Argv(1);
2270 if (cls.state == ca_connected)
2272 c = Cvar_FindVar(cvarname);
2273 // LordHavoc: if there is no such cvar or if it is private, send a
2274 // reply indicating that it has no value
2275 if(!c || (c->flags & CVAR_PRIVATE))
2276 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2278 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2281 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2285 if (cls.state != ca_dedicated)
2289 for(;i<svs.maxclients;i++)
2290 if(svs.clients[i].active && svs.clients[i].netconnection)
2292 host_client = &svs.clients[i];
2293 Host_ClientCommands("sendcvar %s\n", cvarname);
2298 static void MaxPlayers_f(void)
2302 if (Cmd_Argc() != 2)
2304 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
2310 Con_Print("maxplayers can not be changed while a server is running.\n");
2314 n = atoi(Cmd_Argv(1));
2315 n = bound(1, n, MAX_SCOREBOARD);
2316 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2319 Mem_Free(svs.clients);
2321 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
2323 Cvar_Set ("deathmatch", "0");
2325 Cvar_Set ("deathmatch", "1");
2328 //=============================================================================
2330 // QuakeWorld commands
2333 =====================
2336 Send the rest of the command line over as
2337 an unconnected command.
2338 =====================
2340 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2344 lhnetsocket_t *mysocket;
2346 if (!rcon_password.string || !rcon_password.string[0])
2348 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2352 for (i = 0;rcon_password.string[i];i++)
2354 if (ISWHITESPACE(rcon_password.string[i]))
2356 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2362 to = cls.netcon->peeraddress;
2365 if (!rcon_address.string[0])
2367 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2370 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2372 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2375 // simply put together the rcon packet and send it
2376 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2381 ====================
2384 user <name or userid>
2386 Dump userdata / masterdata for a user
2387 ====================
2389 void Host_User_f (void) // credit: taken from QuakeWorld
2394 if (Cmd_Argc() != 2)
2396 Con_Printf ("Usage: user <username / userid>\n");
2400 uid = atoi(Cmd_Argv(1));
2402 for (i = 0;i < cl.maxclients;i++)
2404 if (!cl.scores[i].name[0])
2406 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2408 InfoString_Print(cl.scores[i].qw_userinfo);
2412 Con_Printf ("User not in server.\n");
2416 ====================
2419 Dump userids for all current players
2420 ====================
2422 void Host_Users_f (void) // credit: taken from QuakeWorld
2428 Con_Printf ("userid frags name\n");
2429 Con_Printf ("------ ----- ----\n");
2430 for (i = 0;i < cl.maxclients;i++)
2432 if (cl.scores[i].name[0])
2434 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2439 Con_Printf ("%i total users\n", c);
2444 Host_FullServerinfo_f
2446 Sent by server when serverinfo changes
2449 // TODO: shouldn't this be a cvar instead?
2450 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2453 if (Cmd_Argc() != 2)
2455 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2459 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2460 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2461 cl.qw_teamplay = atoi(temp);
2468 Allow clients to change userinfo
2472 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2479 if (Cmd_Argc() != 2)
2481 Con_Printf ("fullinfo <complete info string>\n");
2491 while (*s && *s != '\\')
2497 Con_Printf ("MISSING VALUE\n");
2503 while (*s && *s != '\\')
2510 CL_SetInfo(key, value, false, false, false, false);
2518 Allow clients to change userinfo
2521 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2523 if (Cmd_Argc() == 1)
2525 InfoString_Print(cls.userinfo);
2528 if (Cmd_Argc() != 3)
2530 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2533 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2537 ====================
2540 packet <destination> <contents>
2542 Contents allows \n escape character
2543 ====================
2545 void Host_Packet_f (void) // credit: taken from QuakeWorld
2551 lhnetaddress_t address;
2552 lhnetsocket_t *mysocket;
2554 if (Cmd_Argc() != 3)
2556 Con_Printf ("packet <destination> <contents>\n");
2560 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2562 Con_Printf ("Bad address\n");
2568 send[0] = send[1] = send[2] = send[3] = 0xff;
2570 l = (int)strlen (in);
2571 for (i=0 ; i<l ; i++)
2573 if (out >= send + sizeof(send) - 1)
2575 if (in[i] == '\\' && in[i+1] == 'n')
2580 else if (in[i] == '\\' && in[i+1] == '0')
2585 else if (in[i] == '\\' && in[i+1] == 't')
2590 else if (in[i] == '\\' && in[i+1] == 'r')
2595 else if (in[i] == '\\' && in[i+1] == '"')
2604 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2606 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2608 NetConn_Write(mysocket, send, out - send, &address);
2612 ====================
2615 Send back ping and packet loss update for all current players to this player
2616 ====================
2618 void Host_Pings_f (void)
2620 int i, j, ping, packetloss;
2623 if (!host_client->netconnection)
2626 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2628 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2629 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2631 for (i = 0;i < svs.maxclients;i++)
2634 if (svs.clients[i].netconnection)
2635 for (j = 0;j < NETGRAPH_PACKETS;j++)
2636 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2638 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2639 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2640 ping = bound(0, ping, 9999);
2641 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2643 // send qw_svc_updateping and qw_svc_updatepl messages
2644 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2645 MSG_WriteShort(&host_client->netconnection->message, ping);
2646 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2647 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2651 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2652 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2653 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2656 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2657 MSG_WriteString(&host_client->netconnection->message, "\n");
2660 void Host_PingPLReport_f(void)
2664 if (l > cl.maxclients)
2666 for (i = 0;i < l;i++)
2668 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2669 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2673 //=============================================================================
2680 void Host_InitCommands (void)
2682 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2684 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2685 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2686 if (gamemode == GAME_NEHAHRA)
2688 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2689 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2690 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2691 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2692 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2696 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2697 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2698 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2699 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2700 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2702 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2703 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2704 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2705 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2706 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)");
2707 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2708 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2709 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2710 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2711 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2712 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2713 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2714 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2715 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2716 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2718 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2719 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2720 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2722 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2723 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2724 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2725 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2727 Cvar_RegisterVariable (&cl_name);
2728 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2729 Cvar_RegisterVariable (&cl_color);
2730 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2731 Cvar_RegisterVariable (&cl_rate);
2732 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2733 if (gamemode == GAME_NEHAHRA)
2735 Cvar_RegisterVariable (&cl_pmodel);
2736 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2739 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2740 Cvar_RegisterVariable (&cl_playermodel);
2741 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2742 Cvar_RegisterVariable (&cl_playerskin);
2743 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2745 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2746 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2747 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)");
2748 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2750 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2752 Cvar_RegisterVariable (&rcon_password);
2753 Cvar_RegisterVariable (&rcon_address);
2754 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)");
2755 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2756 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2757 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2758 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2759 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2760 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2761 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2762 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2764 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)");
2765 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)");
2767 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)");
2768 Cvar_RegisterVariable (&r_fixtrans_auto);
2770 Cvar_RegisterVariable (&team);
2771 Cvar_RegisterVariable (&skin);
2772 Cvar_RegisterVariable (&noaim);
2774 Cvar_RegisterVariable(&sv_cheats);
2775 Cvar_RegisterVariable(&sv_adminnick);
2776 Cvar_RegisterVariable(&sv_status_privacy);
2777 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2780 void Host_NoOperation_f(void)