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;
90 if (strcmp(Cmd_Argv(1), "1") == 0)
92 else if (strcmp(Cmd_Argv(1), "2") == 0)
96 for (players = 0, i = 0;i < svs.maxclients;i++)
97 if (svs.clients[i].active)
99 print ("host: %s\n", Cvar_VariableString ("hostname"));
100 print ("version: %s build %s\n", gamename, buildstring);
101 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
102 print ("map: %s\n", sv.name);
103 print ("timing: %s\n", Host_TimingReport());
104 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
107 print ("^2IP %%pl ping time frags no name\n");
109 print ("^5IP no name\n");
111 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
118 if (in == 0 || in == 1)
120 seconds = (int)(realtime - client->connecttime);
121 minutes = seconds / 60;
124 seconds -= (minutes * 60);
125 hours = minutes / 60;
127 minutes -= (hours * 60);
133 if (client->netconnection)
134 for (j = 0;j < NETGRAPH_PACKETS;j++)
135 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
137 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
138 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
141 if(sv_status_privacy.integer && cmd_source != src_command)
142 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
144 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
146 frags = client->frags;
148 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
150 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
156 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
157 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
161 frags = atoi(qcstatus);
165 if (in == 0) // default layout
167 print ("#%-3u ", i+1);
168 print ("%-16.16s ", client->name);
169 print ("%4i ", frags);
170 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
173 else if (in == 1) // extended layout
175 k%2 ? print("^3") : print("^7");
176 print ("%-21s ", ip);
177 print ("%2i ", packetloss);
178 print ("%4i ", ping);
179 print ("%2i:%02i:%02i ", hours, minutes, seconds);
180 print ("%4i ", frags);
181 print ("#%-3u ", i+1);
182 print ("^7%s\n", client->name);
184 else if (in == 2) // reduced layout
186 k%2 ? print("^3") : print("^7");
187 print ("%-21s ", ip);
188 print ("#%-3u ", i+1);
189 print ("^7%s\n", client->name);
201 Sets client to godmode
204 void Host_God_f (void)
208 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
212 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
213 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
214 SV_ClientPrint("godmode OFF\n");
216 SV_ClientPrint("godmode ON\n");
219 void Host_Notarget_f (void)
223 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
227 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
228 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
229 SV_ClientPrint("notarget OFF\n");
231 SV_ClientPrint("notarget ON\n");
234 qboolean noclip_anglehack;
236 void Host_Noclip_f (void)
240 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
244 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
246 noclip_anglehack = true;
247 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
248 SV_ClientPrint("noclip ON\n");
252 noclip_anglehack = false;
253 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
254 SV_ClientPrint("noclip OFF\n");
262 Sets client to flymode
265 void Host_Fly_f (void)
269 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
273 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
275 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
276 SV_ClientPrint("flymode ON\n");
280 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
281 SV_ClientPrint("flymode OFF\n");
292 void Host_Pings_f (void); // called by Host_Ping_f
293 void Host_Ping_f (void)
297 void (*print) (const char *fmt, ...);
299 if (cmd_source == src_command)
301 // if running a client, try to send over network so the client's ping report parser will see the report
302 if (cls.state == ca_connected)
304 Cmd_ForwardToServer ();
310 print = SV_ClientPrintf;
315 print("Client ping times:\n");
316 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
320 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
323 // 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)
324 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
329 ===============================================================================
333 ===============================================================================
337 ======================
342 command from the console. Active clients are kicked off.
343 ======================
345 void Host_Map_f (void)
347 char level[MAX_QPATH];
351 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
355 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
356 if (gamemode == GAME_DELUXEQUAKE)
357 Cvar_Set("warpmark", "");
359 cls.demonum = -1; // stop demo loop in case this fails
362 Host_ShutdownServer();
367 svs.serverflags = 0; // haven't completed an episode yet
368 allowcheats = sv_cheats.integer != 0;
369 strlcpy(level, Cmd_Argv(1), sizeof(level));
370 SV_SpawnServer(level);
371 if (sv.active && cls.state == ca_disconnected)
372 CL_EstablishConnection("local:1");
379 Goes to a new map, taking all clients along
382 void Host_Changelevel_f (void)
384 char level[MAX_QPATH];
388 Con_Print("changelevel <levelname> : continue game on a new level\n");
401 SV_SaveSpawnparms ();
403 allowcheats = sv_cheats.integer != 0;
404 strlcpy(level, Cmd_Argv(1), sizeof(level));
405 SV_SpawnServer(level);
406 if (sv.active && cls.state == ca_disconnected)
407 CL_EstablishConnection("local:1");
414 Restarts the current server for a dead player
417 void Host_Restart_f (void)
419 char mapname[MAX_QPATH];
423 Con_Print("restart : restart current level\n");
428 Con_Print("Only the server may restart\n");
435 allowcheats = sv_cheats.integer != 0;
436 strlcpy(mapname, sv.name, sizeof(mapname));
437 SV_SpawnServer(mapname);
438 if (sv.active && cls.state == ca_disconnected)
439 CL_EstablishConnection("local:1");
446 This command causes the client to wait for the signon messages again.
447 This is sent just before a server changes levels
450 void Host_Reconnect_f (void)
453 // if not connected, reconnect to the most recent server
456 // if we have connected to a server recently, the userinfo
457 // will still contain its IP address, so get the address...
458 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
460 CL_EstablishConnection(temp);
462 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
465 // if connected, do something based on protocol
466 if (cls.protocol == PROTOCOL_QUAKEWORLD)
468 // quakeworld can just re-login
469 if (cls.qw_downloadmemory) // don't change when downloading
474 if (cls.state == ca_connected && cls.signon < SIGNONS)
476 Con_Printf("reconnecting...\n");
477 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
478 MSG_WriteString(&cls.netcon->message, "new");
483 // netquake uses reconnect on level changes (silly)
486 Con_Print("reconnect : wait for signon messages again\n");
491 Con_Print("reconnect: no signon, ignoring reconnect\n");
494 cls.signon = 0; // need new connection messages
499 =====================
502 User command to connect to server
503 =====================
505 void Host_Connect_f (void)
509 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
512 CL_EstablishConnection(Cmd_Argv(1));
517 ===============================================================================
521 ===============================================================================
524 #define SAVEGAME_VERSION 5
526 void Host_Savegame_to (const char *name)
529 int i, lightstyles = 64;
530 char comment[SAVEGAME_COMMENT_LENGTH+1];
533 // first we have to figure out if this can be saved in 64 lightstyles
534 // (for Quake compatibility)
535 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
536 if (sv.lightstyles[i][0])
539 isserver = !strcmp(PRVM_NAME, "server");
541 Con_Printf("Saving game to %s...\n", name);
542 f = FS_OpenRealFile(name, "wb", false);
545 Con_Print("ERROR: couldn't open.\n");
549 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
551 memset(comment, 0, sizeof(comment));
553 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);
555 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
556 // convert space to _ to make stdio happy
557 // LordHavoc: convert control characters to _ as well
558 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
559 if (ISWHITESPACEORCONTROL(comment[i]))
561 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
563 FS_Printf(f, "%s\n", comment);
566 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
567 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
568 FS_Printf(f, "%d\n", current_skill);
569 FS_Printf(f, "%s\n", sv.name);
570 FS_Printf(f, "%f\n",sv.time);
574 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
575 FS_Printf(f, "(dummy)\n");
576 FS_Printf(f, "%d\n", 0);
577 FS_Printf(f, "%s\n", "(dummy)");
578 FS_Printf(f, "%f\n", realtime);
581 // write the light styles
582 for (i=0 ; i<lightstyles ; i++)
584 if (isserver && sv.lightstyles[i][0])
585 FS_Printf(f, "%s\n", sv.lightstyles[i]);
590 PRVM_ED_WriteGlobals (f);
591 for (i=0 ; i<prog->num_edicts ; i++)
593 FS_Printf(f,"// edict %d\n", i);
594 //Con_Printf("edict %d...\n", i);
595 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
600 FS_Printf(f,"// DarkPlaces extended savegame\n");
601 // darkplaces extension - extra lightstyles, support for color lightstyles
602 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
603 if (isserver && sv.lightstyles[i][0])
604 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
606 // darkplaces extension - model precaches
607 for (i=1 ; i<MAX_MODELS ; i++)
608 if (sv.model_precache[i][0])
609 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
611 // darkplaces extension - sound precaches
612 for (i=1 ; i<MAX_SOUNDS ; i++)
613 if (sv.sound_precache[i][0])
614 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
619 Con_Print("done.\n");
627 void Host_Savegame_f (void)
629 char name[MAX_QPATH];
633 Con_Print("Can't save - no server running.\n");
639 // singleplayer checks
642 Con_Print("Can't save in intermission.\n");
646 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
648 Con_Print("Can't savegame with a dead player\n");
653 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");
657 Con_Print("save <savename> : save a game\n");
661 if (strstr(Cmd_Argv(1), ".."))
663 Con_Print("Relative pathnames are not allowed.\n");
667 strlcpy (name, Cmd_Argv(1), sizeof (name));
668 FS_DefaultExtension (name, ".sav", sizeof (name));
671 Host_Savegame_to(name);
681 void Host_Loadgame_f (void)
683 char filename[MAX_QPATH];
684 char mapname[MAX_QPATH];
694 float spawn_parms[NUM_SPAWN_PARMS];
698 Con_Print("load <savename> : load a game\n");
702 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
703 FS_DefaultExtension (filename, ".sav", sizeof (filename));
705 Con_Printf("Loading game from %s...\n", filename);
707 // stop playing demos
708 if (cls.demoplayback)
714 cls.demonum = -1; // stop demo loop in case this fails
716 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
719 Con_Print("ERROR: couldn't open.\n");
723 if(developer_entityparsing.integer)
724 Con_Printf("Host_Loadgame_f: loading version\n");
727 COM_ParseToken_Simple(&t, false, false);
728 version = atoi(com_token);
729 if (version != SAVEGAME_VERSION)
732 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
736 if(developer_entityparsing.integer)
737 Con_Printf("Host_Loadgame_f: loading description\n");
740 COM_ParseToken_Simple(&t, false, false);
742 for (i = 0;i < NUM_SPAWN_PARMS;i++)
744 COM_ParseToken_Simple(&t, false, false);
745 spawn_parms[i] = atof(com_token);
748 COM_ParseToken_Simple(&t, false, false);
749 // this silliness is so we can load 1.06 save files, which have float skill values
750 current_skill = (int)(atof(com_token) + 0.5);
751 Cvar_SetValue ("skill", (float)current_skill);
753 if(developer_entityparsing.integer)
754 Con_Printf("Host_Loadgame_f: loading mapname\n");
757 COM_ParseToken_Simple(&t, false, false);
758 strlcpy (mapname, com_token, sizeof(mapname));
760 if(developer_entityparsing.integer)
761 Con_Printf("Host_Loadgame_f: loading time\n");
764 COM_ParseToken_Simple(&t, false, false);
765 time = atof(com_token);
767 allowcheats = sv_cheats.integer != 0;
769 if(developer_entityparsing.integer)
770 Con_Printf("Host_Loadgame_f: spawning server\n");
772 SV_SpawnServer (mapname);
776 Con_Print("Couldn't load map\n");
779 sv.paused = true; // pause until all clients connect
782 if(developer_entityparsing.integer)
783 Con_Printf("Host_Loadgame_f: loading light styles\n");
785 // load the light styles
791 for (i = 0;i < MAX_LIGHTSTYLES;i++)
795 COM_ParseToken_Simple(&t, false, false);
796 // if this is a 64 lightstyle savegame produced by Quake, stop now
797 // we have to check this because darkplaces may save more than 64
798 if (com_token[0] == '{')
803 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
806 if(developer_entityparsing.integer)
807 Con_Printf("Host_Loadgame_f: skipping until globals\n");
809 // now skip everything before the first opening brace
810 // (this is for forward compatibility, so that older versions (at
811 // least ones with this fix) can load savegames with extra data before the
812 // first brace, as might be produced by a later engine version)
816 if (!COM_ParseToken_Simple(&t, false, false))
818 if (com_token[0] == '{')
825 // load the edicts out of the savegame file
830 while (COM_ParseToken_Simple(&t, false, false))
831 if (!strcmp(com_token, "}"))
833 if (!COM_ParseToken_Simple(&start, false, false))
838 if (strcmp(com_token,"{"))
841 Host_Error ("First token isn't a brace");
846 if(developer_entityparsing.integer)
847 Con_Printf("Host_Loadgame_f: loading globals\n");
849 // parse the global vars
850 PRVM_ED_ParseGlobals (start);
855 if (entnum >= MAX_EDICTS)
858 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
860 while (entnum >= prog->max_edicts)
861 PRVM_MEM_IncreaseEdicts();
862 ent = PRVM_EDICT_NUM(entnum);
863 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
864 ent->priv.server->free = false;
866 if(developer_entityparsing.integer)
867 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
869 PRVM_ED_ParseEdict (start, ent);
871 // link it into the bsp tree
872 if (!ent->priv.server->free)
873 SV_LinkEdict (ent, false);
880 prog->num_edicts = entnum;
883 for (i = 0;i < NUM_SPAWN_PARMS;i++)
884 svs.clients[0].spawn_parms[i] = spawn_parms[i];
886 if(developer_entityparsing.integer)
887 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
889 // read extended data if present
890 // the extended data is stored inside a /* */ comment block, which the
891 // parser intentionally skips, so we have to check for it manually here
894 while (*end == '\r' || *end == '\n')
896 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
898 if(developer_entityparsing.integer)
899 Con_Printf("Host_Loadgame_f: loading extended data\n");
901 Con_Printf("Loading extended DarkPlaces savegame\n");
903 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
904 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
905 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
906 while (COM_ParseToken_Simple(&t, false, false))
908 if (!strcmp(com_token, "sv.lightstyles"))
910 COM_ParseToken_Simple(&t, false, false);
912 COM_ParseToken_Simple(&t, false, false);
913 if (i >= 0 && i < MAX_LIGHTSTYLES)
914 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
916 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
918 else if (!strcmp(com_token, "sv.model_precache"))
920 COM_ParseToken_Simple(&t, false, false);
922 COM_ParseToken_Simple(&t, false, false);
923 if (i >= 0 && i < MAX_MODELS)
925 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
926 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
929 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
931 else if (!strcmp(com_token, "sv.sound_precache"))
933 COM_ParseToken_Simple(&t, false, false);
935 COM_ParseToken_Simple(&t, false, false);
936 if (i >= 0 && i < MAX_SOUNDS)
937 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
939 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
941 // skip any trailing text or unrecognized commands
942 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
949 if(developer_entityparsing.integer)
950 Con_Printf("Host_Loadgame_f: finished\n");
954 // make sure we're connected to loopback
955 if (sv.active && cls.state == ca_disconnected)
956 CL_EstablishConnection("local:1");
959 //============================================================================
962 ======================
964 ======================
966 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
967 void Host_Name_f (void)
970 qboolean valid_colors;
971 char newName[sizeof(host_client->name)];
973 if (Cmd_Argc () == 1)
975 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
979 if (Cmd_Argc () == 2)
980 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
982 strlcpy (newName, Cmd_Args(), sizeof (newName));
984 if (cmd_source == src_command)
986 Cvar_Set ("_cl_name", newName);
990 if (realtime < host_client->nametime)
992 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
996 host_client->nametime = realtime + 5;
998 // point the string back at updateclient->name to keep it safe
999 strlcpy (host_client->name, newName, sizeof (host_client->name));
1001 for (i = 0, j = 0;host_client->name[i];i++)
1002 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1003 host_client->name[j++] = host_client->name[i];
1004 host_client->name[j] = 0;
1006 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1007 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1009 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1010 host_client->name[sizeof(host_client->name) - 1] = 0;
1011 host_client->name[0] = STRING_COLOR_TAG;
1012 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1015 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1016 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1019 l = strlen(host_client->name);
1020 if(l < sizeof(host_client->name) - 1)
1022 // duplicate the color tag to escape it
1023 host_client->name[i] = STRING_COLOR_TAG;
1024 host_client->name[i+1] = 0;
1025 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1029 // remove the last character to fix the color code
1030 host_client->name[l-1] = 0;
1031 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1035 // find the last color tag offset and decide if we need to add a reset tag
1036 for (i = 0, j = -1;host_client->name[i];i++)
1038 if (host_client->name[i] == STRING_COLOR_TAG)
1040 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1043 // if this happens to be a reset tag then we don't need one
1044 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1049 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]))
1055 if (host_client->name[i+1] == STRING_COLOR_TAG)
1062 // does not end in the default color string, so add it
1063 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1064 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1066 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1067 if (strcmp(host_client->old_name, host_client->name))
1069 if (host_client->spawned)
1070 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1071 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1072 // send notification to all clients
1073 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1074 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1075 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1076 SV_WriteNetnameIntoDemo(host_client);
1081 ======================
1083 ======================
1085 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1086 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1087 void Host_Playermodel_f (void)
1090 char newPath[sizeof(host_client->playermodel)];
1092 if (Cmd_Argc () == 1)
1094 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1098 if (Cmd_Argc () == 2)
1099 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1101 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1103 for (i = 0, j = 0;newPath[i];i++)
1104 if (newPath[i] != '\r' && newPath[i] != '\n')
1105 newPath[j++] = newPath[i];
1108 if (cmd_source == src_command)
1110 Cvar_Set ("_cl_playermodel", newPath);
1115 if (realtime < host_client->nametime)
1117 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1121 host_client->nametime = realtime + 5;
1124 // point the string back at updateclient->name to keep it safe
1125 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1126 if( prog->fieldoffsets.playermodel >= 0 )
1127 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1128 if (strcmp(host_client->old_model, host_client->playermodel))
1130 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1131 /*// send notification to all clients
1132 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1133 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1134 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1139 ======================
1141 ======================
1143 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1144 void Host_Playerskin_f (void)
1147 char newPath[sizeof(host_client->playerskin)];
1149 if (Cmd_Argc () == 1)
1151 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1155 if (Cmd_Argc () == 2)
1156 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1158 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1160 for (i = 0, j = 0;newPath[i];i++)
1161 if (newPath[i] != '\r' && newPath[i] != '\n')
1162 newPath[j++] = newPath[i];
1165 if (cmd_source == src_command)
1167 Cvar_Set ("_cl_playerskin", newPath);
1172 if (realtime < host_client->nametime)
1174 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1178 host_client->nametime = realtime + 5;
1181 // point the string back at updateclient->name to keep it safe
1182 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1183 if( prog->fieldoffsets.playerskin >= 0 )
1184 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1185 if (strcmp(host_client->old_skin, host_client->playerskin))
1187 //if (host_client->spawned)
1188 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1189 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1190 /*// send notification to all clients
1191 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1192 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1193 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1197 void Host_Version_f (void)
1199 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1202 void Host_Say(qboolean teamonly)
1208 // LordHavoc: long say messages
1210 qboolean fromServer = false;
1212 if (cmd_source == src_command)
1214 if (cls.state == ca_dedicated)
1221 Cmd_ForwardToServer ();
1226 if (Cmd_Argc () < 2)
1229 if (!teamplay.integer)
1239 // note this uses the chat prefix \001
1240 if (!fromServer && !teamonly)
1241 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1242 else if (!fromServer && teamonly)
1243 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1244 else if(*(sv_adminnick.string))
1245 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1247 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1248 p2 = text + strlen(text);
1249 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1251 if (p2[-1] == '\"' && quoted)
1256 strlcat(text, "\n", sizeof(text));
1258 // note: save is not a valid edict if fromServer is true
1260 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1261 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1262 SV_ClientPrint(text);
1265 if (cls.state == ca_dedicated)
1266 Con_Print(&text[1]);
1270 void Host_Say_f(void)
1276 void Host_Say_Team_f(void)
1282 void Host_Tell_f(void)
1284 const char *playername_start = NULL;
1285 size_t playername_length = 0;
1286 int playernumber = 0;
1289 const char *p1, *p2;
1290 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1291 qboolean fromServer = false;
1293 if (cmd_source == src_command)
1295 if (cls.state == ca_dedicated)
1299 Cmd_ForwardToServer ();
1304 if (Cmd_Argc () < 2)
1307 // note this uses the chat prefix \001
1309 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1310 else if(*(sv_adminnick.string))
1311 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1313 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1316 p2 = p1 + strlen(p1);
1317 // remove the target name
1318 while (p1 < p2 && *p1 == ' ')
1323 while (p1 < p2 && *p1 == ' ')
1325 while (p1 < p2 && isdigit(*p1))
1327 playernumber = playernumber * 10 + (*p1 - '0');
1335 playername_start = p1;
1336 while (p1 < p2 && *p1 != '"')
1338 playername_length = p1 - playername_start;
1344 playername_start = p1;
1345 while (p1 < p2 && *p1 != ' ')
1347 playername_length = p1 - playername_start;
1349 while (p1 < p2 && *p1 == ' ')
1351 if(playername_start)
1353 // set playernumber to the right client
1355 if(playername_length >= sizeof(namebuf))
1358 Con_Print("Host_Tell: too long player name/ID\n");
1360 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1363 memcpy(namebuf, playername_start, playername_length);
1364 namebuf[playername_length] = 0;
1365 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1367 if (!svs.clients[playernumber].active)
1369 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1373 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1376 Con_Print("Host_Tell: invalid player name/ID\n");
1378 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1381 // remove trailing newlines
1382 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1384 // remove quotes if present
1390 else if (fromServer)
1391 Con_Print("Host_Tell: missing end quote\n");
1393 SV_ClientPrint("Host_Tell: missing end quote\n");
1395 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1398 return; // empty say
1399 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1405 host_client = svs.clients + playernumber;
1406 SV_ClientPrint(text);
1416 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1417 void Host_Color(int changetop, int changebottom)
1419 int top, bottom, playercolor;
1421 // get top and bottom either from the provided values or the current values
1422 // (allows changing only top or bottom, or both at once)
1423 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1424 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1428 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1434 playercolor = top*16 + bottom;
1436 if (cmd_source == src_command)
1438 Cvar_SetValueQuick(&cl_color, playercolor);
1442 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1445 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1447 Con_DPrint("Calling SV_ChangeTeam\n");
1448 prog->globals.server->time = sv.time;
1449 prog->globals.generic[OFS_PARM0] = playercolor;
1450 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1451 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1456 if (host_client->edict)
1458 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1459 val->_float = playercolor;
1460 host_client->edict->fields.server->team = bottom + 1;
1462 host_client->colors = playercolor;
1463 if (host_client->old_colors != host_client->colors)
1465 host_client->old_colors = host_client->colors;
1466 // send notification to all clients
1467 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1468 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1469 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1474 void Host_Color_f(void)
1478 if (Cmd_Argc() == 1)
1480 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1481 Con_Print("color <0-15> [0-15]\n");
1485 if (Cmd_Argc() == 2)
1486 top = bottom = atoi(Cmd_Argv(1));
1489 top = atoi(Cmd_Argv(1));
1490 bottom = atoi(Cmd_Argv(2));
1492 Host_Color(top, bottom);
1495 void Host_TopColor_f(void)
1497 if (Cmd_Argc() == 1)
1499 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1500 Con_Print("topcolor <0-15>\n");
1504 Host_Color(atoi(Cmd_Argv(1)), -1);
1507 void Host_BottomColor_f(void)
1509 if (Cmd_Argc() == 1)
1511 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1512 Con_Print("bottomcolor <0-15>\n");
1516 Host_Color(-1, atoi(Cmd_Argv(1)));
1519 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1520 void Host_Rate_f(void)
1524 if (Cmd_Argc() != 2)
1526 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1527 Con_Print("rate <bytespersecond>\n");
1531 rate = atoi(Cmd_Argv(1));
1533 if (cmd_source == src_command)
1535 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1539 host_client->rate = rate;
1547 void Host_Kill_f (void)
1549 if (host_client->edict->fields.server->health <= 0)
1551 SV_ClientPrint("Can't suicide -- already dead!\n");
1555 prog->globals.server->time = sv.time;
1556 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1557 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1566 void Host_Pause_f (void)
1568 if (!pausable.integer)
1569 SV_ClientPrint("Pause not allowed.\n");
1573 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1574 // send notification to all clients
1575 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1576 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1581 ======================
1583 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1584 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1585 ======================
1587 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)"};
1588 static void Host_PModel_f (void)
1593 if (Cmd_Argc () == 1)
1595 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1598 i = atoi(Cmd_Argv(1));
1600 if (cmd_source == src_command)
1602 if (cl_pmodel.integer == i)
1604 Cvar_SetValue ("_cl_pmodel", i);
1605 if (cls.state == ca_connected)
1606 Cmd_ForwardToServer ();
1610 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1614 //===========================================================================
1622 void Host_PreSpawn_f (void)
1624 if (host_client->spawned)
1626 Con_Print("prespawn not valid -- already spawned\n");
1630 if (host_client->netconnection)
1632 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1633 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1634 MSG_WriteByte (&host_client->netconnection->message, 2);
1635 host_client->sendsignon = 0; // enable unlimited sends again
1638 // reset the name change timer because the client will send name soon
1639 host_client->nametime = 0;
1647 void Host_Spawn_f (void)
1651 int stats[MAX_CL_STATS];
1653 if (host_client->spawned)
1655 Con_Print("Spawn not valid -- already spawned\n");
1659 // reset name change timer again because they might want to change name
1660 // again in the first 5 seconds after connecting
1661 host_client->nametime = 0;
1663 // LordHavoc: moved this above the QC calls at FrikaC's request
1664 // LordHavoc: commented this out
1665 //if (host_client->netconnection)
1666 // SZ_Clear (&host_client->netconnection->message);
1668 // run the entrance script
1671 // loaded games are fully initialized already
1672 if (prog->funcoffsets.RestoreGame)
1674 Con_DPrint("Calling RestoreGame\n");
1675 prog->globals.server->time = sv.time;
1676 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1677 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1682 //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);
1684 // copy spawn parms out of the client_t
1685 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1686 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1688 // call the spawn function
1689 host_client->clientconnectcalled = true;
1690 prog->globals.server->time = sv.time;
1691 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1692 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1694 if (cls.state == ca_dedicated)
1695 Con_Printf("%s connected\n", host_client->name);
1697 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1700 if (!host_client->netconnection)
1703 // send time of update
1704 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1705 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1707 // send all current names, colors, and frag counts
1708 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1710 if (!client->active)
1712 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1713 MSG_WriteByte (&host_client->netconnection->message, i);
1714 MSG_WriteString (&host_client->netconnection->message, client->name);
1715 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1716 MSG_WriteByte (&host_client->netconnection->message, i);
1717 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1718 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1719 MSG_WriteByte (&host_client->netconnection->message, i);
1720 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1723 // send all current light styles
1724 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1726 if (sv.lightstyles[i][0])
1728 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1729 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1730 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1735 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1736 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1737 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1739 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1740 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1741 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1743 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1744 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1745 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1747 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1748 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1749 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1752 // Never send a roll angle, because savegames can catch the server
1753 // in a state where it is expecting the client to correct the angle
1754 // and it won't happen if the game was just loaded, so you wind up
1755 // with a permanent head tilt
1758 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1759 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1760 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1761 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1765 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1766 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1767 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1768 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1771 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1773 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1774 MSG_WriteByte (&host_client->netconnection->message, 3);
1782 void Host_Begin_f (void)
1784 host_client->spawned = true;
1786 // LordHavoc: note: this code also exists in SV_DropClient
1790 for (i = 0;i < svs.maxclients;i++)
1791 if (svs.clients[i].active && !svs.clients[i].spawned)
1793 if (i == svs.maxclients)
1795 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1796 sv.paused = sv.loadgame = false; // we're basically done with loading now
1801 //===========================================================================
1808 Kicks a user off of the server
1811 void Host_Kick_f (void)
1814 const char *message = NULL;
1817 qboolean byNumber = false;
1825 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1827 i = (int)(atof(Cmd_Argv(2)) - 1);
1828 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1834 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1836 if (!host_client->active)
1838 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1843 if (i < svs.maxclients)
1845 if (cmd_source == src_command)
1847 if (cls.state == ca_dedicated)
1850 who = cl_name.string;
1855 // can't kick yourself!
1856 if (host_client == save)
1861 message = Cmd_Args();
1862 COM_ParseToken_Simple(&message, false, false);
1865 message++; // skip the #
1866 while (*message == ' ') // skip white space
1868 message += strlen(Cmd_Argv(2)); // skip the number
1870 while (*message && *message == ' ')
1874 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1876 SV_ClientPrintf("Kicked by %s\n", who);
1877 SV_DropClient (false); // kicked
1885 ===============================================================================
1889 ===============================================================================
1897 void Host_Give_f (void)
1905 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1910 v = atoi (Cmd_Argv(2));
1924 // MED 01/04/97 added hipnotic give stuff
1925 if (gamemode == GAME_HIPNOTIC)
1930 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1932 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1934 else if (t[0] == '9')
1935 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1936 else if (t[0] == '0')
1937 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1938 else if (t[0] >= '2')
1939 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1944 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1949 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1952 host_client->edict->fields.server->ammo_shells = v;
1955 if (gamemode == GAME_ROGUE)
1957 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1960 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1961 host_client->edict->fields.server->ammo_nails = v;
1966 host_client->edict->fields.server->ammo_nails = v;
1970 if (gamemode == GAME_ROGUE)
1972 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1976 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1977 host_client->edict->fields.server->ammo_nails = v;
1982 if (gamemode == GAME_ROGUE)
1984 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
1988 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1989 host_client->edict->fields.server->ammo_rockets = v;
1994 host_client->edict->fields.server->ammo_rockets = v;
1998 if (gamemode == GAME_ROGUE)
2000 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
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->health = v;
2013 if (gamemode == GAME_ROGUE)
2015 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2019 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2020 host_client->edict->fields.server->ammo_cells = v;
2025 host_client->edict->fields.server->ammo_cells = v;
2029 if (gamemode == GAME_ROGUE)
2031 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2035 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2036 host_client->edict->fields.server->ammo_cells = v;
2043 prvm_edict_t *FindViewthing (void)
2048 for (i=0 ; i<prog->num_edicts ; i++)
2050 e = PRVM_EDICT_NUM(i);
2051 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2054 Con_Print("No viewthing on map\n");
2063 void Host_Viewmodel_f (void)
2072 e = FindViewthing ();
2077 m = Mod_ForName (Cmd_Argv(1), false, true, false);
2078 if (!m || !m->loaded || !m->Draw)
2080 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2084 e->fields.server->frame = 0;
2085 cl.model_precache[(int)e->fields.server->modelindex] = m;
2093 void Host_Viewframe_f (void)
2103 e = FindViewthing ();
2107 m = cl.model_precache[(int)e->fields.server->modelindex];
2109 f = atoi(Cmd_Argv(1));
2110 if (f >= m->numframes)
2113 e->fields.server->frame = f;
2117 void PrintFrameName (dp_model_t *m, int frame)
2120 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2122 Con_Printf("frame %i\n", frame);
2130 void Host_Viewnext_f (void)
2139 e = FindViewthing ();
2143 m = cl.model_precache[(int)e->fields.server->modelindex];
2145 e->fields.server->frame = e->fields.server->frame + 1;
2146 if (e->fields.server->frame >= m->numframes)
2147 e->fields.server->frame = m->numframes - 1;
2149 PrintFrameName (m, (int)e->fields.server->frame);
2157 void Host_Viewprev_f (void)
2166 e = FindViewthing ();
2171 m = cl.model_precache[(int)e->fields.server->modelindex];
2173 e->fields.server->frame = e->fields.server->frame - 1;
2174 if (e->fields.server->frame < 0)
2175 e->fields.server->frame = 0;
2177 PrintFrameName (m, (int)e->fields.server->frame);
2181 ===============================================================================
2185 ===============================================================================
2194 void Host_Startdemos_f (void)
2198 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2204 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2207 Con_DPrintf("%i demo(s) in loop\n", c);
2209 for (i=1 ; i<c+1 ; i++)
2210 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2212 // LordHavoc: clear the remaining slots
2213 for (;i <= MAX_DEMOS;i++)
2214 cls.demos[i-1][0] = 0;
2216 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2230 Return to looping demos
2233 void Host_Demos_f (void)
2235 if (cls.state == ca_dedicated)
2237 if (cls.demonum == -1)
2247 Return to looping demos
2250 void Host_Stopdemo_f (void)
2252 if (!cls.demoplayback)
2255 Host_ShutdownServer ();
2258 void Host_SendCvar_f (void)
2262 const char *cvarname;
2267 cvarname = Cmd_Argv(1);
2268 if (cls.state == ca_connected)
2270 c = Cvar_FindVar(cvarname);
2271 // LordHavoc: if there is no such cvar or if it is private, send a
2272 // reply indicating that it has no value
2273 if(!c || (c->flags & CVAR_PRIVATE))
2274 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2276 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2279 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2283 if (cls.state != ca_dedicated)
2287 for(;i<svs.maxclients;i++)
2288 if(svs.clients[i].active && svs.clients[i].netconnection)
2290 host_client = &svs.clients[i];
2291 Host_ClientCommands("sendcvar %s\n", cvarname);
2296 static void MaxPlayers_f(void)
2300 if (Cmd_Argc() != 2)
2302 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
2308 Con_Print("maxplayers can not be changed while a server is running.\n");
2312 n = atoi(Cmd_Argv(1));
2313 n = bound(1, n, MAX_SCOREBOARD);
2314 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2317 Mem_Free(svs.clients);
2319 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
2321 Cvar_Set ("deathmatch", "0");
2323 Cvar_Set ("deathmatch", "1");
2326 //=============================================================================
2328 // QuakeWorld commands
2331 =====================
2334 Send the rest of the command line over as
2335 an unconnected command.
2336 =====================
2338 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2342 lhnetsocket_t *mysocket;
2344 if (!rcon_password.string || !rcon_password.string[0])
2346 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2350 for (i = 0;rcon_password.string[i];i++)
2352 if (ISWHITESPACE(rcon_password.string[i]))
2354 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2360 to = cls.netcon->peeraddress;
2363 if (!rcon_address.string[0])
2365 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2368 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2370 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2373 // simply put together the rcon packet and send it
2374 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2379 ====================
2382 user <name or userid>
2384 Dump userdata / masterdata for a user
2385 ====================
2387 void Host_User_f (void) // credit: taken from QuakeWorld
2392 if (Cmd_Argc() != 2)
2394 Con_Printf ("Usage: user <username / userid>\n");
2398 uid = atoi(Cmd_Argv(1));
2400 for (i = 0;i < cl.maxclients;i++)
2402 if (!cl.scores[i].name[0])
2404 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2406 InfoString_Print(cl.scores[i].qw_userinfo);
2410 Con_Printf ("User not in server.\n");
2414 ====================
2417 Dump userids for all current players
2418 ====================
2420 void Host_Users_f (void) // credit: taken from QuakeWorld
2426 Con_Printf ("userid frags name\n");
2427 Con_Printf ("------ ----- ----\n");
2428 for (i = 0;i < cl.maxclients;i++)
2430 if (cl.scores[i].name[0])
2432 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2437 Con_Printf ("%i total users\n", c);
2442 Host_FullServerinfo_f
2444 Sent by server when serverinfo changes
2447 // TODO: shouldn't this be a cvar instead?
2448 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2451 if (Cmd_Argc() != 2)
2453 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2457 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2458 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2459 cl.qw_teamplay = atoi(temp);
2466 Allow clients to change userinfo
2470 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2477 if (Cmd_Argc() != 2)
2479 Con_Printf ("fullinfo <complete info string>\n");
2489 while (*s && *s != '\\')
2495 Con_Printf ("MISSING VALUE\n");
2501 while (*s && *s != '\\')
2508 CL_SetInfo(key, value, false, false, false, false);
2516 Allow clients to change userinfo
2519 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2521 if (Cmd_Argc() == 1)
2523 InfoString_Print(cls.userinfo);
2526 if (Cmd_Argc() != 3)
2528 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2531 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2535 ====================
2538 packet <destination> <contents>
2540 Contents allows \n escape character
2541 ====================
2543 void Host_Packet_f (void) // credit: taken from QuakeWorld
2549 lhnetaddress_t address;
2550 lhnetsocket_t *mysocket;
2552 if (Cmd_Argc() != 3)
2554 Con_Printf ("packet <destination> <contents>\n");
2558 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2560 Con_Printf ("Bad address\n");
2566 send[0] = send[1] = send[2] = send[3] = 0xff;
2568 l = (int)strlen (in);
2569 for (i=0 ; i<l ; i++)
2571 if (out >= send + sizeof(send) - 1)
2573 if (in[i] == '\\' && in[i+1] == 'n')
2578 else if (in[i] == '\\' && in[i+1] == '0')
2583 else if (in[i] == '\\' && in[i+1] == 't')
2588 else if (in[i] == '\\' && in[i+1] == 'r')
2593 else if (in[i] == '\\' && in[i+1] == '"')
2602 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2604 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2606 NetConn_Write(mysocket, send, out - send, &address);
2610 ====================
2613 Send back ping and packet loss update for all current players to this player
2614 ====================
2616 void Host_Pings_f (void)
2618 int i, j, ping, packetloss;
2621 if (!host_client->netconnection)
2624 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2626 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2627 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2629 for (i = 0;i < svs.maxclients;i++)
2632 if (svs.clients[i].netconnection)
2633 for (j = 0;j < NETGRAPH_PACKETS;j++)
2634 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2636 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2637 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2638 ping = bound(0, ping, 9999);
2639 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2641 // send qw_svc_updateping and qw_svc_updatepl messages
2642 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2643 MSG_WriteShort(&host_client->netconnection->message, ping);
2644 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2645 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2649 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2650 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2651 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2654 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2655 MSG_WriteString(&host_client->netconnection->message, "\n");
2658 void Host_PingPLReport_f(void)
2662 if (l > cl.maxclients)
2664 for (i = 0;i < l;i++)
2666 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2667 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2671 //=============================================================================
2678 void Host_InitCommands (void)
2680 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2682 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2683 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2684 if (gamemode == GAME_NEHAHRA)
2686 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2687 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2688 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2689 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2690 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2694 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2695 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2696 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2697 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2698 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2700 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2701 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2702 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2703 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2704 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)");
2705 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2706 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2707 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2708 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2709 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2710 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2711 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2712 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2713 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2714 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2716 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2717 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2718 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2720 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2721 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2722 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2723 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2725 Cvar_RegisterVariable (&cl_name);
2726 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2727 Cvar_RegisterVariable (&cl_color);
2728 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2729 Cvar_RegisterVariable (&cl_rate);
2730 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2731 if (gamemode == GAME_NEHAHRA)
2733 Cvar_RegisterVariable (&cl_pmodel);
2734 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2737 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2738 Cvar_RegisterVariable (&cl_playermodel);
2739 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2740 Cvar_RegisterVariable (&cl_playerskin);
2741 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2743 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2744 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2745 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)");
2746 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2748 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2750 Cvar_RegisterVariable (&rcon_password);
2751 Cvar_RegisterVariable (&rcon_address);
2752 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)");
2753 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2754 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2755 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2756 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2757 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2758 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2759 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2760 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2762 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)");
2763 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)");
2765 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)");
2766 Cvar_RegisterVariable (&r_fixtrans_auto);
2768 Cvar_RegisterVariable (&team);
2769 Cvar_RegisterVariable (&skin);
2770 Cvar_RegisterVariable (&noaim);
2772 Cvar_RegisterVariable(&sv_cheats);
2773 Cvar_RegisterVariable(&sv_adminnick);
2774 Cvar_RegisterVariable(&sv_status_privacy);
2775 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2778 void Host_NoOperation_f(void)