2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 // for secure rcon authentication
31 cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
32 cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
33 cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
34 cvar_t sv_status_show_qcstatus = {CVAR_SAVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."};
35 cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands"};
36 cvar_t rcon_secure = {0, "rcon_secure", "1", "force secure rcon authentication"};
37 cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
38 cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
39 cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
40 cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
41 cvar_t r_fixtrans_auto = {0, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"};
42 qboolean allowcheats = false;
44 extern qboolean host_shuttingdown;
45 extern cvar_t developer_entityparsing;
53 void Host_Quit_f (void)
56 Con_Printf("shutting down already!\n");
66 void Host_Status_f (void)
70 int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
71 void (*print) (const char *fmt, ...);
75 if (cmd_source == src_command)
77 // if running a client, try to send over network so the client's status report parser will see the report
78 if (cls.state == ca_connected)
80 Cmd_ForwardToServer ();
86 print = SV_ClientPrintf;
91 if(cmd_source == src_command)
97 if (strcmp(Cmd_Argv(1), "1") == 0)
99 else if (strcmp(Cmd_Argv(1), "2") == 0)
103 for (players = 0, i = 0;i < svs.maxclients;i++)
104 if (svs.clients[i].active)
106 print ("host: %s\n", Cvar_VariableString ("hostname"));
107 print ("version: %s build %s\n", gamename, buildstring);
108 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
109 print ("map: %s\n", sv.name);
110 print ("timing: %s\n", Host_TimingReport());
111 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
114 print ("^2IP %%pl ping time frags no name\n");
116 print ("^5IP no name\n");
118 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
125 if (in == 0 || in == 1)
127 seconds = (int)(realtime - client->connecttime);
128 minutes = seconds / 60;
131 seconds -= (minutes * 60);
132 hours = minutes / 60;
134 minutes -= (hours * 60);
140 if (client->netconnection)
141 for (j = 0;j < NETGRAPH_PACKETS;j++)
142 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
144 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
145 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
148 if(sv_status_privacy.integer && cmd_source != src_command)
149 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
151 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
153 frags = client->frags;
155 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
157 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
163 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
164 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
168 frags = atoi(qcstatus);
172 if (in == 0) // default layout
174 print ("#%-3u ", i+1);
175 print ("%-16.16s ", client->name);
176 print ("%4i ", frags);
177 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
180 else if (in == 1) // extended layout
182 k%2 ? print("^3") : print("^7");
183 print ("%-21s ", ip);
184 print ("%2i ", packetloss);
185 print ("%4i ", ping);
186 print ("%2i:%02i:%02i ", hours, minutes, seconds);
187 print ("%4i ", frags);
188 print ("#%-3u ", i+1);
189 print ("^7%s\n", client->name);
191 else if (in == 2) // reduced layout
193 k%2 ? print("^3") : print("^7");
194 print ("%-21s ", ip);
195 print ("#%-3u ", i+1);
196 print ("^7%s\n", client->name);
200 if(cmd_source == src_command)
209 Sets client to godmode
212 void Host_God_f (void)
216 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
220 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
221 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
222 SV_ClientPrint("godmode OFF\n");
224 SV_ClientPrint("godmode ON\n");
227 void Host_Notarget_f (void)
231 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
235 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
236 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
237 SV_ClientPrint("notarget OFF\n");
239 SV_ClientPrint("notarget ON\n");
242 qboolean noclip_anglehack;
244 void Host_Noclip_f (void)
248 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
252 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
254 noclip_anglehack = true;
255 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
256 SV_ClientPrint("noclip ON\n");
260 noclip_anglehack = false;
261 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
262 SV_ClientPrint("noclip OFF\n");
270 Sets client to flymode
273 void Host_Fly_f (void)
277 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
281 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
283 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
284 SV_ClientPrint("flymode ON\n");
288 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
289 SV_ClientPrint("flymode OFF\n");
300 void Host_Pings_f (void); // called by Host_Ping_f
301 void Host_Ping_f (void)
305 void (*print) (const char *fmt, ...);
307 if (cmd_source == src_command)
309 // if running a client, try to send over network so the client's ping report parser will see the report
310 if (cls.state == ca_connected)
312 Cmd_ForwardToServer ();
318 print = SV_ClientPrintf;
323 print("Client ping times:\n");
324 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
328 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
331 // now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report)
332 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
337 ===============================================================================
341 ===============================================================================
345 ======================
350 command from the console. Active clients are kicked off.
351 ======================
353 void Host_Map_f (void)
355 char level[MAX_QPATH];
359 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
363 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
364 if (gamemode == GAME_DELUXEQUAKE)
365 Cvar_Set("warpmark", "");
367 cls.demonum = -1; // stop demo loop in case this fails
370 Host_ShutdownServer();
372 if(svs.maxclients != svs.maxclients_next)
374 svs.maxclients = svs.maxclients_next;
376 Mem_Free(svs.clients);
377 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
383 svs.serverflags = 0; // haven't completed an episode yet
384 allowcheats = sv_cheats.integer != 0;
385 strlcpy(level, Cmd_Argv(1), sizeof(level));
386 SV_SpawnServer(level);
387 if (sv.active && cls.state == ca_disconnected)
388 CL_EstablishConnection("local:1");
395 Goes to a new map, taking all clients along
398 void Host_Changelevel_f (void)
400 char level[MAX_QPATH];
404 Con_Print("changelevel <levelname> : continue game on a new level\n");
417 SV_SaveSpawnparms ();
419 allowcheats = sv_cheats.integer != 0;
420 strlcpy(level, Cmd_Argv(1), sizeof(level));
421 SV_SpawnServer(level);
422 if (sv.active && cls.state == ca_disconnected)
423 CL_EstablishConnection("local:1");
430 Restarts the current server for a dead player
433 void Host_Restart_f (void)
435 char mapname[MAX_QPATH];
439 Con_Print("restart : restart current level\n");
444 Con_Print("Only the server may restart\n");
451 allowcheats = sv_cheats.integer != 0;
452 strlcpy(mapname, sv.name, sizeof(mapname));
453 SV_SpawnServer(mapname);
454 if (sv.active && cls.state == ca_disconnected)
455 CL_EstablishConnection("local:1");
462 This command causes the client to wait for the signon messages again.
463 This is sent just before a server changes levels
466 void Host_Reconnect_f (void)
469 // if not connected, reconnect to the most recent server
472 // if we have connected to a server recently, the userinfo
473 // will still contain its IP address, so get the address...
474 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
476 CL_EstablishConnection(temp);
478 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
481 // if connected, do something based on protocol
482 if (cls.protocol == PROTOCOL_QUAKEWORLD)
484 // quakeworld can just re-login
485 if (cls.qw_downloadmemory) // don't change when downloading
490 if (cls.state == ca_connected && cls.signon < SIGNONS)
492 Con_Printf("reconnecting...\n");
493 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
494 MSG_WriteString(&cls.netcon->message, "new");
499 // netquake uses reconnect on level changes (silly)
502 Con_Print("reconnect : wait for signon messages again\n");
507 Con_Print("reconnect: no signon, ignoring reconnect\n");
510 cls.signon = 0; // need new connection messages
515 =====================
518 User command to connect to server
519 =====================
521 void Host_Connect_f (void)
525 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
528 CL_EstablishConnection(Cmd_Argv(1));
533 ===============================================================================
537 ===============================================================================
540 #define SAVEGAME_VERSION 5
542 void Host_Savegame_to (const char *name)
545 int i, lightstyles = 64;
546 char comment[SAVEGAME_COMMENT_LENGTH+1];
549 // first we have to figure out if this can be saved in 64 lightstyles
550 // (for Quake compatibility)
551 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
552 if (sv.lightstyles[i][0])
555 isserver = !strcmp(PRVM_NAME, "server");
557 Con_Printf("Saving game to %s...\n", name);
558 f = FS_OpenRealFile(name, "wb", false);
561 Con_Print("ERROR: couldn't open.\n");
565 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
567 memset(comment, 0, sizeof(comment));
569 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);
571 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
572 // convert space to _ to make stdio happy
573 // LordHavoc: convert control characters to _ as well
574 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
575 if (ISWHITESPACEORCONTROL(comment[i]))
577 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
579 FS_Printf(f, "%s\n", comment);
582 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
583 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
584 FS_Printf(f, "%d\n", current_skill);
585 FS_Printf(f, "%s\n", sv.name);
586 FS_Printf(f, "%f\n",sv.time);
590 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
591 FS_Printf(f, "(dummy)\n");
592 FS_Printf(f, "%d\n", 0);
593 FS_Printf(f, "%s\n", "(dummy)");
594 FS_Printf(f, "%f\n", realtime);
597 // write the light styles
598 for (i=0 ; i<lightstyles ; i++)
600 if (isserver && sv.lightstyles[i][0])
601 FS_Printf(f, "%s\n", sv.lightstyles[i]);
606 PRVM_ED_WriteGlobals (f);
607 for (i=0 ; i<prog->num_edicts ; i++)
609 FS_Printf(f,"// edict %d\n", i);
610 //Con_Printf("edict %d...\n", i);
611 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
616 FS_Printf(f,"// DarkPlaces extended savegame\n");
617 // darkplaces extension - extra lightstyles, support for color lightstyles
618 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
619 if (isserver && sv.lightstyles[i][0])
620 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
622 // darkplaces extension - model precaches
623 for (i=1 ; i<MAX_MODELS ; i++)
624 if (sv.model_precache[i][0])
625 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
627 // darkplaces extension - sound precaches
628 for (i=1 ; i<MAX_SOUNDS ; i++)
629 if (sv.sound_precache[i][0])
630 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
635 Con_Print("done.\n");
643 void Host_Savegame_f (void)
645 char name[MAX_QPATH];
649 Con_Print("Can't save - no server running.\n");
655 // singleplayer checks
658 Con_Print("Can't save in intermission.\n");
662 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
664 Con_Print("Can't savegame with a dead player\n");
669 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");
673 Con_Print("save <savename> : save a game\n");
677 if (strstr(Cmd_Argv(1), ".."))
679 Con_Print("Relative pathnames are not allowed.\n");
683 strlcpy (name, Cmd_Argv(1), sizeof (name));
684 FS_DefaultExtension (name, ".sav", sizeof (name));
687 Host_Savegame_to(name);
697 void Host_Loadgame_f (void)
699 char filename[MAX_QPATH];
700 char mapname[MAX_QPATH];
710 float spawn_parms[NUM_SPAWN_PARMS];
714 Con_Print("load <savename> : load a game\n");
718 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
719 FS_DefaultExtension (filename, ".sav", sizeof (filename));
721 Con_Printf("Loading game from %s...\n", filename);
723 // stop playing demos
724 if (cls.demoplayback)
730 cls.demonum = -1; // stop demo loop in case this fails
732 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
735 Con_Print("ERROR: couldn't open.\n");
739 if(developer_entityparsing.integer)
740 Con_Printf("Host_Loadgame_f: loading version\n");
743 COM_ParseToken_Simple(&t, false, false);
744 version = atoi(com_token);
745 if (version != SAVEGAME_VERSION)
748 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
752 if(developer_entityparsing.integer)
753 Con_Printf("Host_Loadgame_f: loading description\n");
756 COM_ParseToken_Simple(&t, false, false);
758 for (i = 0;i < NUM_SPAWN_PARMS;i++)
760 COM_ParseToken_Simple(&t, false, false);
761 spawn_parms[i] = atof(com_token);
764 COM_ParseToken_Simple(&t, false, false);
765 // this silliness is so we can load 1.06 save files, which have float skill values
766 current_skill = (int)(atof(com_token) + 0.5);
767 Cvar_SetValue ("skill", (float)current_skill);
769 if(developer_entityparsing.integer)
770 Con_Printf("Host_Loadgame_f: loading mapname\n");
773 COM_ParseToken_Simple(&t, false, false);
774 strlcpy (mapname, com_token, sizeof(mapname));
776 if(developer_entityparsing.integer)
777 Con_Printf("Host_Loadgame_f: loading time\n");
780 COM_ParseToken_Simple(&t, false, false);
781 time = atof(com_token);
783 allowcheats = sv_cheats.integer != 0;
785 if(developer_entityparsing.integer)
786 Con_Printf("Host_Loadgame_f: spawning server\n");
788 SV_SpawnServer (mapname);
792 Con_Print("Couldn't load map\n");
795 sv.paused = true; // pause until all clients connect
798 if(developer_entityparsing.integer)
799 Con_Printf("Host_Loadgame_f: loading light styles\n");
801 // load the light styles
807 for (i = 0;i < MAX_LIGHTSTYLES;i++)
811 COM_ParseToken_Simple(&t, false, false);
812 // if this is a 64 lightstyle savegame produced by Quake, stop now
813 // we have to check this because darkplaces may save more than 64
814 if (com_token[0] == '{')
819 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
822 if(developer_entityparsing.integer)
823 Con_Printf("Host_Loadgame_f: skipping until globals\n");
825 // now skip everything before the first opening brace
826 // (this is for forward compatibility, so that older versions (at
827 // least ones with this fix) can load savegames with extra data before the
828 // first brace, as might be produced by a later engine version)
832 if (!COM_ParseToken_Simple(&t, false, false))
834 if (com_token[0] == '{')
841 // load the edicts out of the savegame file
846 while (COM_ParseToken_Simple(&t, false, false))
847 if (!strcmp(com_token, "}"))
849 if (!COM_ParseToken_Simple(&start, false, false))
854 if (strcmp(com_token,"{"))
857 Host_Error ("First token isn't a brace");
862 if(developer_entityparsing.integer)
863 Con_Printf("Host_Loadgame_f: loading globals\n");
865 // parse the global vars
866 PRVM_ED_ParseGlobals (start);
871 if (entnum >= MAX_EDICTS)
874 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
876 while (entnum >= prog->max_edicts)
877 PRVM_MEM_IncreaseEdicts();
878 ent = PRVM_EDICT_NUM(entnum);
879 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
880 ent->priv.server->free = false;
882 if(developer_entityparsing.integer)
883 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
885 PRVM_ED_ParseEdict (start, ent);
887 // link it into the bsp tree
888 if (!ent->priv.server->free)
889 SV_LinkEdict (ent, false);
896 prog->num_edicts = entnum;
899 for (i = 0;i < NUM_SPAWN_PARMS;i++)
900 svs.clients[0].spawn_parms[i] = spawn_parms[i];
902 if(developer_entityparsing.integer)
903 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
905 // read extended data if present
906 // the extended data is stored inside a /* */ comment block, which the
907 // parser intentionally skips, so we have to check for it manually here
910 while (*end == '\r' || *end == '\n')
912 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
914 if(developer_entityparsing.integer)
915 Con_Printf("Host_Loadgame_f: loading extended data\n");
917 Con_Printf("Loading extended DarkPlaces savegame\n");
919 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
920 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
921 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
922 while (COM_ParseToken_Simple(&t, false, false))
924 if (!strcmp(com_token, "sv.lightstyles"))
926 COM_ParseToken_Simple(&t, false, false);
928 COM_ParseToken_Simple(&t, false, false);
929 if (i >= 0 && i < MAX_LIGHTSTYLES)
930 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
932 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
934 else if (!strcmp(com_token, "sv.model_precache"))
936 COM_ParseToken_Simple(&t, false, false);
938 COM_ParseToken_Simple(&t, false, false);
939 if (i >= 0 && i < MAX_MODELS)
941 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
942 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL);
945 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
947 else if (!strcmp(com_token, "sv.sound_precache"))
949 COM_ParseToken_Simple(&t, false, false);
951 COM_ParseToken_Simple(&t, false, false);
952 if (i >= 0 && i < MAX_SOUNDS)
953 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
955 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
957 // skip any trailing text or unrecognized commands
958 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
965 if(developer_entityparsing.integer)
966 Con_Printf("Host_Loadgame_f: finished\n");
970 // make sure we're connected to loopback
971 if (sv.active && cls.state == ca_disconnected)
972 CL_EstablishConnection("local:1");
975 //============================================================================
978 ======================
980 ======================
982 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
983 void Host_Name_f (void)
986 qboolean valid_colors;
987 char newName[sizeof(host_client->name)];
989 if (Cmd_Argc () == 1)
991 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
995 if (Cmd_Argc () == 2)
996 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
998 strlcpy (newName, Cmd_Args(), sizeof (newName));
1000 if (cmd_source == src_command)
1002 Cvar_Set ("_cl_name", newName);
1006 if (realtime < host_client->nametime)
1008 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1012 host_client->nametime = realtime + 5;
1014 // point the string back at updateclient->name to keep it safe
1015 strlcpy (host_client->name, newName, sizeof (host_client->name));
1017 for (i = 0, j = 0;host_client->name[i];i++)
1018 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1019 host_client->name[j++] = host_client->name[i];
1020 host_client->name[j] = 0;
1022 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1023 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1025 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1026 host_client->name[sizeof(host_client->name) - 1] = 0;
1027 host_client->name[0] = STRING_COLOR_TAG;
1028 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1031 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1032 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1035 l = strlen(host_client->name);
1036 if(l < sizeof(host_client->name) - 1)
1038 // duplicate the color tag to escape it
1039 host_client->name[i] = STRING_COLOR_TAG;
1040 host_client->name[i+1] = 0;
1041 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1045 // remove the last character to fix the color code
1046 host_client->name[l-1] = 0;
1047 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1051 // find the last color tag offset and decide if we need to add a reset tag
1052 for (i = 0, j = -1;host_client->name[i];i++)
1054 if (host_client->name[i] == STRING_COLOR_TAG)
1056 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1059 // if this happens to be a reset tag then we don't need one
1060 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1065 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]))
1071 if (host_client->name[i+1] == STRING_COLOR_TAG)
1078 // does not end in the default color string, so add it
1079 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1080 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1082 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1083 if (strcmp(host_client->old_name, host_client->name))
1085 if (host_client->spawned)
1086 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1087 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1088 // send notification to all clients
1089 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1090 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1091 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1092 SV_WriteNetnameIntoDemo(host_client);
1097 ======================
1099 ======================
1101 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1102 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1103 void Host_Playermodel_f (void)
1106 char newPath[sizeof(host_client->playermodel)];
1108 if (Cmd_Argc () == 1)
1110 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1114 if (Cmd_Argc () == 2)
1115 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1117 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1119 for (i = 0, j = 0;newPath[i];i++)
1120 if (newPath[i] != '\r' && newPath[i] != '\n')
1121 newPath[j++] = newPath[i];
1124 if (cmd_source == src_command)
1126 Cvar_Set ("_cl_playermodel", newPath);
1131 if (realtime < host_client->nametime)
1133 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1137 host_client->nametime = realtime + 5;
1140 // point the string back at updateclient->name to keep it safe
1141 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1142 if( prog->fieldoffsets.playermodel >= 0 )
1143 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1144 if (strcmp(host_client->old_model, host_client->playermodel))
1146 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1147 /*// send notification to all clients
1148 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1149 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1150 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1155 ======================
1157 ======================
1159 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1160 void Host_Playerskin_f (void)
1163 char newPath[sizeof(host_client->playerskin)];
1165 if (Cmd_Argc () == 1)
1167 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1171 if (Cmd_Argc () == 2)
1172 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1174 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1176 for (i = 0, j = 0;newPath[i];i++)
1177 if (newPath[i] != '\r' && newPath[i] != '\n')
1178 newPath[j++] = newPath[i];
1181 if (cmd_source == src_command)
1183 Cvar_Set ("_cl_playerskin", newPath);
1188 if (realtime < host_client->nametime)
1190 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1194 host_client->nametime = realtime + 5;
1197 // point the string back at updateclient->name to keep it safe
1198 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1199 if( prog->fieldoffsets.playerskin >= 0 )
1200 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1201 if (strcmp(host_client->old_skin, host_client->playerskin))
1203 //if (host_client->spawned)
1204 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1205 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1206 /*// send notification to all clients
1207 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1208 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1209 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1213 void Host_Version_f (void)
1215 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1218 void Host_Say(qboolean teamonly)
1224 // LordHavoc: long say messages
1226 qboolean fromServer = false;
1228 if (cmd_source == src_command)
1230 if (cls.state == ca_dedicated)
1237 Cmd_ForwardToServer ();
1242 if (Cmd_Argc () < 2)
1245 if (!teamplay.integer)
1255 // note this uses the chat prefix \001
1256 if (!fromServer && !teamonly)
1257 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1258 else if (!fromServer && teamonly)
1259 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1260 else if(*(sv_adminnick.string))
1261 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1263 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1264 p2 = text + strlen(text);
1265 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1267 if (p2[-1] == '\"' && quoted)
1272 strlcat(text, "\n", sizeof(text));
1274 // note: save is not a valid edict if fromServer is true
1276 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1277 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1278 SV_ClientPrint(text);
1281 if (cls.state == ca_dedicated)
1282 Con_Print(&text[1]);
1286 void Host_Say_f(void)
1292 void Host_Say_Team_f(void)
1298 void Host_Tell_f(void)
1300 const char *playername_start = NULL;
1301 size_t playername_length = 0;
1302 int playernumber = 0;
1305 const char *p1, *p2;
1306 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1307 qboolean fromServer = false;
1309 if (cmd_source == src_command)
1311 if (cls.state == ca_dedicated)
1315 Cmd_ForwardToServer ();
1320 if (Cmd_Argc () < 2)
1323 // note this uses the chat prefix \001
1325 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1326 else if(*(sv_adminnick.string))
1327 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1329 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1332 p2 = p1 + strlen(p1);
1333 // remove the target name
1334 while (p1 < p2 && *p1 == ' ')
1339 while (p1 < p2 && *p1 == ' ')
1341 while (p1 < p2 && isdigit(*p1))
1343 playernumber = playernumber * 10 + (*p1 - '0');
1351 playername_start = p1;
1352 while (p1 < p2 && *p1 != '"')
1354 playername_length = p1 - playername_start;
1360 playername_start = p1;
1361 while (p1 < p2 && *p1 != ' ')
1363 playername_length = p1 - playername_start;
1365 while (p1 < p2 && *p1 == ' ')
1367 if(playername_start)
1369 // set playernumber to the right client
1371 if(playername_length >= sizeof(namebuf))
1374 Con_Print("Host_Tell: too long player name/ID\n");
1376 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1379 memcpy(namebuf, playername_start, playername_length);
1380 namebuf[playername_length] = 0;
1381 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1383 if (!svs.clients[playernumber].active)
1385 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1389 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1392 Con_Print("Host_Tell: invalid player name/ID\n");
1394 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1397 // remove trailing newlines
1398 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1400 // remove quotes if present
1406 else if (fromServer)
1407 Con_Print("Host_Tell: missing end quote\n");
1409 SV_ClientPrint("Host_Tell: missing end quote\n");
1411 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1414 return; // empty say
1415 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1421 host_client = svs.clients + playernumber;
1422 SV_ClientPrint(text);
1432 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1433 void Host_Color(int changetop, int changebottom)
1435 int top, bottom, playercolor;
1437 // get top and bottom either from the provided values or the current values
1438 // (allows changing only top or bottom, or both at once)
1439 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1440 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1444 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1450 playercolor = top*16 + bottom;
1452 if (cmd_source == src_command)
1454 Cvar_SetValueQuick(&cl_color, playercolor);
1458 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1461 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1463 Con_DPrint("Calling SV_ChangeTeam\n");
1464 prog->globals.server->time = sv.time;
1465 prog->globals.generic[OFS_PARM0] = playercolor;
1466 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1467 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1472 if (host_client->edict)
1474 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1475 val->_float = playercolor;
1476 host_client->edict->fields.server->team = bottom + 1;
1478 host_client->colors = playercolor;
1479 if (host_client->old_colors != host_client->colors)
1481 host_client->old_colors = host_client->colors;
1482 // send notification to all clients
1483 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1484 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1485 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1490 void Host_Color_f(void)
1494 if (Cmd_Argc() == 1)
1496 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1497 Con_Print("color <0-15> [0-15]\n");
1501 if (Cmd_Argc() == 2)
1502 top = bottom = atoi(Cmd_Argv(1));
1505 top = atoi(Cmd_Argv(1));
1506 bottom = atoi(Cmd_Argv(2));
1508 Host_Color(top, bottom);
1511 void Host_TopColor_f(void)
1513 if (Cmd_Argc() == 1)
1515 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1516 Con_Print("topcolor <0-15>\n");
1520 Host_Color(atoi(Cmd_Argv(1)), -1);
1523 void Host_BottomColor_f(void)
1525 if (Cmd_Argc() == 1)
1527 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1528 Con_Print("bottomcolor <0-15>\n");
1532 Host_Color(-1, atoi(Cmd_Argv(1)));
1535 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1536 void Host_Rate_f(void)
1540 if (Cmd_Argc() != 2)
1542 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1543 Con_Print("rate <bytespersecond>\n");
1547 rate = atoi(Cmd_Argv(1));
1549 if (cmd_source == src_command)
1551 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1555 host_client->rate = rate;
1563 void Host_Kill_f (void)
1565 if (host_client->edict->fields.server->health <= 0)
1567 SV_ClientPrint("Can't suicide -- already dead!\n");
1571 prog->globals.server->time = sv.time;
1572 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1573 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1582 void Host_Pause_f (void)
1584 if (!pausable.integer)
1585 SV_ClientPrint("Pause not allowed.\n");
1589 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1590 // send notification to all clients
1591 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1592 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1597 ======================
1599 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1600 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1601 ======================
1603 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)"};
1604 static void Host_PModel_f (void)
1609 if (Cmd_Argc () == 1)
1611 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1614 i = atoi(Cmd_Argv(1));
1616 if (cmd_source == src_command)
1618 if (cl_pmodel.integer == i)
1620 Cvar_SetValue ("_cl_pmodel", i);
1621 if (cls.state == ca_connected)
1622 Cmd_ForwardToServer ();
1626 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1630 //===========================================================================
1638 void Host_PreSpawn_f (void)
1640 if (host_client->spawned)
1642 Con_Print("prespawn not valid -- already spawned\n");
1646 if (host_client->netconnection)
1648 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1649 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1650 MSG_WriteByte (&host_client->netconnection->message, 2);
1651 host_client->sendsignon = 0; // enable unlimited sends again
1654 // reset the name change timer because the client will send name soon
1655 host_client->nametime = 0;
1663 void Host_Spawn_f (void)
1667 int stats[MAX_CL_STATS];
1669 if (host_client->spawned)
1671 Con_Print("Spawn not valid -- already spawned\n");
1675 // reset name change timer again because they might want to change name
1676 // again in the first 5 seconds after connecting
1677 host_client->nametime = 0;
1679 // LordHavoc: moved this above the QC calls at FrikaC's request
1680 // LordHavoc: commented this out
1681 //if (host_client->netconnection)
1682 // SZ_Clear (&host_client->netconnection->message);
1684 // run the entrance script
1687 // loaded games are fully initialized already
1688 if (prog->funcoffsets.RestoreGame)
1690 Con_DPrint("Calling RestoreGame\n");
1691 prog->globals.server->time = sv.time;
1692 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1693 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1698 //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);
1700 // copy spawn parms out of the client_t
1701 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1702 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1704 // call the spawn function
1705 host_client->clientconnectcalled = true;
1706 prog->globals.server->time = sv.time;
1707 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1708 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1710 if (cls.state == ca_dedicated)
1711 Con_Printf("%s connected\n", host_client->name);
1713 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1716 if (!host_client->netconnection)
1719 // send time of update
1720 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1721 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1723 // send all current names, colors, and frag counts
1724 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1726 if (!client->active)
1728 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1729 MSG_WriteByte (&host_client->netconnection->message, i);
1730 MSG_WriteString (&host_client->netconnection->message, client->name);
1731 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1732 MSG_WriteByte (&host_client->netconnection->message, i);
1733 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1734 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1735 MSG_WriteByte (&host_client->netconnection->message, i);
1736 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1739 // send all current light styles
1740 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1742 if (sv.lightstyles[i][0])
1744 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1745 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1746 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1751 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1752 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1753 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1755 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1756 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1757 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1759 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1760 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1761 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1763 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1764 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1765 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1768 // Never send a roll angle, because savegames can catch the server
1769 // in a state where it is expecting the client to correct the angle
1770 // and it won't happen if the game was just loaded, so you wind up
1771 // with a permanent head tilt
1774 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1775 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1776 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1777 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1781 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1782 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1783 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1784 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1787 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1789 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1790 MSG_WriteByte (&host_client->netconnection->message, 3);
1798 void Host_Begin_f (void)
1800 host_client->spawned = true;
1802 // LordHavoc: note: this code also exists in SV_DropClient
1806 for (i = 0;i < svs.maxclients;i++)
1807 if (svs.clients[i].active && !svs.clients[i].spawned)
1809 if (i == svs.maxclients)
1811 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1812 sv.paused = sv.loadgame = false; // we're basically done with loading now
1817 //===========================================================================
1824 Kicks a user off of the server
1827 void Host_Kick_f (void)
1830 const char *message = NULL;
1833 qboolean byNumber = false;
1841 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1843 i = (int)(atof(Cmd_Argv(2)) - 1);
1844 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1850 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1852 if (!host_client->active)
1854 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1859 if (i < svs.maxclients)
1861 if (cmd_source == src_command)
1863 if (cls.state == ca_dedicated)
1866 who = cl_name.string;
1871 // can't kick yourself!
1872 if (host_client == save)
1877 message = Cmd_Args();
1878 COM_ParseToken_Simple(&message, false, false);
1881 message++; // skip the #
1882 while (*message == ' ') // skip white space
1884 message += strlen(Cmd_Argv(2)); // skip the number
1886 while (*message && *message == ' ')
1890 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1892 SV_ClientPrintf("Kicked by %s\n", who);
1893 SV_DropClient (false); // kicked
1901 ===============================================================================
1905 ===============================================================================
1913 void Host_Give_f (void)
1921 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1926 v = atoi (Cmd_Argv(2));
1940 // MED 01/04/97 added hipnotic give stuff
1941 if (gamemode == GAME_HIPNOTIC)
1946 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1948 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1950 else if (t[0] == '9')
1951 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1952 else if (t[0] == '0')
1953 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1954 else if (t[0] >= '2')
1955 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1960 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1965 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1968 host_client->edict->fields.server->ammo_shells = v;
1971 if (gamemode == GAME_ROGUE)
1973 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1976 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1977 host_client->edict->fields.server->ammo_nails = v;
1982 host_client->edict->fields.server->ammo_nails = v;
1986 if (gamemode == GAME_ROGUE)
1988 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1992 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1993 host_client->edict->fields.server->ammo_nails = v;
1998 if (gamemode == GAME_ROGUE)
2000 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
2004 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2005 host_client->edict->fields.server->ammo_rockets = v;
2010 host_client->edict->fields.server->ammo_rockets = v;
2014 if (gamemode == GAME_ROGUE)
2016 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2020 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2021 host_client->edict->fields.server->ammo_rockets = v;
2026 host_client->edict->fields.server->health = v;
2029 if (gamemode == GAME_ROGUE)
2031 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2035 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2036 host_client->edict->fields.server->ammo_cells = v;
2041 host_client->edict->fields.server->ammo_cells = v;
2045 if (gamemode == GAME_ROGUE)
2047 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2051 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2052 host_client->edict->fields.server->ammo_cells = v;
2059 prvm_edict_t *FindViewthing (void)
2064 for (i=0 ; i<prog->num_edicts ; i++)
2066 e = PRVM_EDICT_NUM(i);
2067 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2070 Con_Print("No viewthing on map\n");
2079 void Host_Viewmodel_f (void)
2088 e = FindViewthing ();
2093 m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
2094 if (!m || !m->loaded || !m->Draw)
2096 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2100 e->fields.server->frame = 0;
2101 cl.model_precache[(int)e->fields.server->modelindex] = m;
2109 void Host_Viewframe_f (void)
2119 e = FindViewthing ();
2123 m = cl.model_precache[(int)e->fields.server->modelindex];
2125 f = atoi(Cmd_Argv(1));
2126 if (f >= m->numframes)
2129 e->fields.server->frame = f;
2133 void PrintFrameName (dp_model_t *m, int frame)
2136 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2138 Con_Printf("frame %i\n", frame);
2146 void Host_Viewnext_f (void)
2155 e = FindViewthing ();
2159 m = cl.model_precache[(int)e->fields.server->modelindex];
2161 e->fields.server->frame = e->fields.server->frame + 1;
2162 if (e->fields.server->frame >= m->numframes)
2163 e->fields.server->frame = m->numframes - 1;
2165 PrintFrameName (m, (int)e->fields.server->frame);
2173 void Host_Viewprev_f (void)
2182 e = FindViewthing ();
2187 m = cl.model_precache[(int)e->fields.server->modelindex];
2189 e->fields.server->frame = e->fields.server->frame - 1;
2190 if (e->fields.server->frame < 0)
2191 e->fields.server->frame = 0;
2193 PrintFrameName (m, (int)e->fields.server->frame);
2197 ===============================================================================
2201 ===============================================================================
2210 void Host_Startdemos_f (void)
2214 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2220 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2223 Con_DPrintf("%i demo(s) in loop\n", c);
2225 for (i=1 ; i<c+1 ; i++)
2226 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2228 // LordHavoc: clear the remaining slots
2229 for (;i <= MAX_DEMOS;i++)
2230 cls.demos[i-1][0] = 0;
2232 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2246 Return to looping demos
2249 void Host_Demos_f (void)
2251 if (cls.state == ca_dedicated)
2253 if (cls.demonum == -1)
2263 Return to looping demos
2266 void Host_Stopdemo_f (void)
2268 if (!cls.demoplayback)
2271 Host_ShutdownServer ();
2274 void Host_SendCvar_f (void)
2278 const char *cvarname;
2283 cvarname = Cmd_Argv(1);
2284 if (cls.state == ca_connected)
2286 c = Cvar_FindVar(cvarname);
2287 // LordHavoc: if there is no such cvar or if it is private, send a
2288 // reply indicating that it has no value
2289 if(!c || (c->flags & CVAR_PRIVATE))
2290 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2292 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2295 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2299 if (cls.state != ca_dedicated)
2303 for(;i<svs.maxclients;i++)
2304 if(svs.clients[i].active && svs.clients[i].netconnection)
2306 host_client = &svs.clients[i];
2307 Host_ClientCommands("sendcvar %s\n", cvarname);
2312 static void MaxPlayers_f(void)
2316 if (Cmd_Argc() != 2)
2318 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
2324 Con_Print("maxplayers can not be changed while a server is running.\n");
2325 Con_Print("It will be changed on next server startup (\"map\" command).\n");
2328 n = atoi(Cmd_Argv(1));
2329 n = bound(1, n, MAX_SCOREBOARD);
2330 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2332 svs.maxclients_next = n;
2334 Cvar_Set ("deathmatch", "0");
2336 Cvar_Set ("deathmatch", "1");
2339 //=============================================================================
2341 // QuakeWorld commands
2344 =====================
2347 Send the rest of the command line over as
2348 an unconnected command.
2349 =====================
2351 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2355 lhnetsocket_t *mysocket;
2357 if (!rcon_password.string || !rcon_password.string[0])
2359 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2363 for (i = 0;rcon_password.string[i];i++)
2365 if (ISWHITESPACE(rcon_password.string[i]))
2367 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2373 to = cls.netcon->peeraddress;
2376 if (!rcon_address.string[0])
2378 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2381 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2383 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2386 // simply put together the rcon packet and send it
2387 if(rcon_secure.integer)
2391 dpsnprintf(argbuf, sizeof(argbuf), "%ld %s", (long) time(NULL), Cmd_Args());
2392 memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24);
2393 HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, strlen(rcon_password.string));
2395 strlcpy(buf + 41, argbuf, sizeof(buf) - 41);
2396 NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to);
2400 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2406 ====================
2409 user <name or userid>
2411 Dump userdata / masterdata for a user
2412 ====================
2414 void Host_User_f (void) // credit: taken from QuakeWorld
2419 if (Cmd_Argc() != 2)
2421 Con_Printf ("Usage: user <username / userid>\n");
2425 uid = atoi(Cmd_Argv(1));
2427 for (i = 0;i < cl.maxclients;i++)
2429 if (!cl.scores[i].name[0])
2431 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2433 InfoString_Print(cl.scores[i].qw_userinfo);
2437 Con_Printf ("User not in server.\n");
2441 ====================
2444 Dump userids for all current players
2445 ====================
2447 void Host_Users_f (void) // credit: taken from QuakeWorld
2453 Con_Printf ("userid frags name\n");
2454 Con_Printf ("------ ----- ----\n");
2455 for (i = 0;i < cl.maxclients;i++)
2457 if (cl.scores[i].name[0])
2459 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2464 Con_Printf ("%i total users\n", c);
2469 Host_FullServerinfo_f
2471 Sent by server when serverinfo changes
2474 // TODO: shouldn't this be a cvar instead?
2475 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2478 if (Cmd_Argc() != 2)
2480 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2484 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2485 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2486 cl.qw_teamplay = atoi(temp);
2493 Allow clients to change userinfo
2497 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2504 if (Cmd_Argc() != 2)
2506 Con_Printf ("fullinfo <complete info string>\n");
2516 while (*s && *s != '\\')
2522 Con_Printf ("MISSING VALUE\n");
2528 while (*s && *s != '\\')
2535 CL_SetInfo(key, value, false, false, false, false);
2543 Allow clients to change userinfo
2546 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2548 if (Cmd_Argc() == 1)
2550 InfoString_Print(cls.userinfo);
2553 if (Cmd_Argc() != 3)
2555 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2558 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2562 ====================
2565 packet <destination> <contents>
2567 Contents allows \n escape character
2568 ====================
2570 void Host_Packet_f (void) // credit: taken from QuakeWorld
2576 lhnetaddress_t address;
2577 lhnetsocket_t *mysocket;
2579 if (Cmd_Argc() != 3)
2581 Con_Printf ("packet <destination> <contents>\n");
2585 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2587 Con_Printf ("Bad address\n");
2593 send[0] = send[1] = send[2] = send[3] = 0xff;
2595 l = (int)strlen (in);
2596 for (i=0 ; i<l ; i++)
2598 if (out >= send + sizeof(send) - 1)
2600 if (in[i] == '\\' && in[i+1] == 'n')
2605 else if (in[i] == '\\' && in[i+1] == '0')
2610 else if (in[i] == '\\' && in[i+1] == 't')
2615 else if (in[i] == '\\' && in[i+1] == 'r')
2620 else if (in[i] == '\\' && in[i+1] == '"')
2629 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2631 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2633 NetConn_Write(mysocket, send, out - send, &address);
2637 ====================
2640 Send back ping and packet loss update for all current players to this player
2641 ====================
2643 void Host_Pings_f (void)
2645 int i, j, ping, packetloss;
2648 if (!host_client->netconnection)
2651 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2653 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2654 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2656 for (i = 0;i < svs.maxclients;i++)
2659 if (svs.clients[i].netconnection)
2660 for (j = 0;j < NETGRAPH_PACKETS;j++)
2661 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2663 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2664 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2665 ping = bound(0, ping, 9999);
2666 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2668 // send qw_svc_updateping and qw_svc_updatepl messages
2669 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2670 MSG_WriteShort(&host_client->netconnection->message, ping);
2671 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2672 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2676 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2677 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2678 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2681 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2682 MSG_WriteString(&host_client->netconnection->message, "\n");
2685 void Host_PingPLReport_f(void)
2689 if (l > cl.maxclients)
2691 for (i = 0;i < l;i++)
2693 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2694 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2698 //=============================================================================
2705 void Host_InitCommands (void)
2707 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2709 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2710 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2711 if (gamemode == GAME_NEHAHRA)
2713 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2714 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2715 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2716 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2717 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2721 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2722 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2723 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2724 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2725 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2727 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2728 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2729 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2730 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2731 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)");
2732 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2733 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2734 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2735 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2736 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2737 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2738 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2739 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2740 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2741 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2743 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2744 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2745 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2747 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2748 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2749 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2750 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2752 Cvar_RegisterVariable (&cl_name);
2753 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2754 Cvar_RegisterVariable (&cl_color);
2755 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2756 Cvar_RegisterVariable (&cl_rate);
2757 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2758 if (gamemode == GAME_NEHAHRA)
2760 Cvar_RegisterVariable (&cl_pmodel);
2761 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2764 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2765 Cvar_RegisterVariable (&cl_playermodel);
2766 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2767 Cvar_RegisterVariable (&cl_playerskin);
2768 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2770 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2771 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2772 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)");
2773 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2775 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2777 Cvar_RegisterVariable (&rcon_password);
2778 Cvar_RegisterVariable (&rcon_address);
2779 Cvar_RegisterVariable (&rcon_secure);
2780 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)");
2781 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2782 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2783 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2784 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2785 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2786 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2787 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2788 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2790 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)");
2791 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)");
2793 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)");
2794 Cvar_RegisterVariable (&r_fixtrans_auto);
2796 Cvar_RegisterVariable (&team);
2797 Cvar_RegisterVariable (&skin);
2798 Cvar_RegisterVariable (&noaim);
2800 Cvar_RegisterVariable(&sv_cheats);
2801 Cvar_RegisterVariable(&sv_adminnick);
2802 Cvar_RegisterVariable(&sv_status_privacy);
2803 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2806 void Host_NoOperation_f(void)