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;
88 if (strcmp(Cmd_Argv(1), "1") == 0)
90 else if (strcmp(Cmd_Argv(1), "2") == 0)
94 for (players = 0, i = 0;i < svs.maxclients;i++)
95 if (svs.clients[i].active)
97 print ("host: %s\n", Cvar_VariableString ("hostname"));
98 print ("version: %s build %s\n", gamename, buildstring);
99 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
100 print ("map: %s\n", sv.name);
101 print ("timing: %s\n", Host_TimingReport());
102 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
105 print ("^2IP %%pl ping time frags no name\n");
107 print ("^5IP no name\n");
109 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
116 if (in == 0 || in == 1)
118 seconds = (int)(realtime - client->connecttime);
119 minutes = seconds / 60;
122 seconds -= (minutes * 60);
123 hours = minutes / 60;
125 minutes -= (hours * 60);
131 if (client->netconnection)
132 for (j = 0;j < NETGRAPH_PACKETS;j++)
133 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
135 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
136 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
139 if(sv_status_privacy.integer && cmd_source != src_command)
140 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
142 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
144 frags = client->frags;
146 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
148 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
154 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
155 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
159 frags = atoi(qcstatus);
163 if (in == 0) // default layout
165 print ("#%-3u ", i+1);
166 print ("%-16.16s ", client->name);
167 print ("%4i ", frags);
168 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
171 else if (in == 1) // extended layout
173 k%2 ? print("^3") : print("^7");
174 print ("%-21s ", ip);
175 print ("%2i ", packetloss);
176 print ("%4i ", ping);
177 print ("%2i:%02i:%02i ", hours, minutes, seconds);
178 print ("%4i ", frags);
179 print ("#%-3u ", i+1);
180 print ("^7%s\n", client->name);
182 else if (in == 2) // reduced layout
184 k%2 ? print("^3") : print("^7");
185 print ("%-21s ", ip);
186 print ("#%-3u ", i+1);
187 print ("^7%s\n", client->name);
197 Sets client to godmode
200 void Host_God_f (void)
204 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
208 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
209 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
210 SV_ClientPrint("godmode OFF\n");
212 SV_ClientPrint("godmode ON\n");
215 void Host_Notarget_f (void)
219 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
223 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
224 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
225 SV_ClientPrint("notarget OFF\n");
227 SV_ClientPrint("notarget ON\n");
230 qboolean noclip_anglehack;
232 void Host_Noclip_f (void)
236 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
240 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
242 noclip_anglehack = true;
243 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
244 SV_ClientPrint("noclip ON\n");
248 noclip_anglehack = false;
249 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
250 SV_ClientPrint("noclip OFF\n");
258 Sets client to flymode
261 void Host_Fly_f (void)
265 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
269 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
271 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
272 SV_ClientPrint("flymode ON\n");
276 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
277 SV_ClientPrint("flymode OFF\n");
288 void Host_Pings_f (void); // called by Host_Ping_f
289 void Host_Ping_f (void)
293 void (*print) (const char *fmt, ...);
295 if (cmd_source == src_command)
297 // if running a client, try to send over network so the client's ping report parser will see the report
298 if (cls.state == ca_connected)
300 Cmd_ForwardToServer ();
306 print = SV_ClientPrintf;
311 print("Client ping times:\n");
312 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
316 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
319 // 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)
320 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
325 ===============================================================================
329 ===============================================================================
333 ======================
338 command from the console. Active clients are kicked off.
339 ======================
341 void Host_Map_f (void)
343 char level[MAX_QPATH];
347 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
351 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
352 if (gamemode == GAME_DELUXEQUAKE)
353 Cvar_Set("warpmark", "");
355 cls.demonum = -1; // stop demo loop in case this fails
358 Host_ShutdownServer();
363 svs.serverflags = 0; // haven't completed an episode yet
364 allowcheats = sv_cheats.integer != 0;
365 strlcpy(level, Cmd_Argv(1), sizeof(level));
366 SV_SpawnServer(level);
367 if (sv.active && cls.state == ca_disconnected)
368 CL_EstablishConnection("local:1");
375 Goes to a new map, taking all clients along
378 void Host_Changelevel_f (void)
380 char level[MAX_QPATH];
384 Con_Print("changelevel <levelname> : continue game on a new level\n");
397 SV_SaveSpawnparms ();
399 allowcheats = sv_cheats.integer != 0;
400 strlcpy(level, Cmd_Argv(1), sizeof(level));
401 SV_SpawnServer(level);
402 if (sv.active && cls.state == ca_disconnected)
403 CL_EstablishConnection("local:1");
410 Restarts the current server for a dead player
413 void Host_Restart_f (void)
415 char mapname[MAX_QPATH];
419 Con_Print("restart : restart current level\n");
424 Con_Print("Only the server may restart\n");
431 allowcheats = sv_cheats.integer != 0;
432 strlcpy(mapname, sv.name, sizeof(mapname));
433 SV_SpawnServer(mapname);
434 if (sv.active && cls.state == ca_disconnected)
435 CL_EstablishConnection("local:1");
442 This command causes the client to wait for the signon messages again.
443 This is sent just before a server changes levels
446 void Host_Reconnect_f (void)
449 // if not connected, reconnect to the most recent server
452 // if we have connected to a server recently, the userinfo
453 // will still contain its IP address, so get the address...
454 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
456 CL_EstablishConnection(temp);
458 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
461 // if connected, do something based on protocol
462 if (cls.protocol == PROTOCOL_QUAKEWORLD)
464 // quakeworld can just re-login
465 if (cls.qw_downloadmemory) // don't change when downloading
470 if (cls.state == ca_connected && cls.signon < SIGNONS)
472 Con_Printf("reconnecting...\n");
473 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
474 MSG_WriteString(&cls.netcon->message, "new");
479 // netquake uses reconnect on level changes (silly)
482 Con_Print("reconnect : wait for signon messages again\n");
487 Con_Print("reconnect: no signon, ignoring reconnect\n");
490 cls.signon = 0; // need new connection messages
495 =====================
498 User command to connect to server
499 =====================
501 void Host_Connect_f (void)
505 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
508 CL_EstablishConnection(Cmd_Argv(1));
513 ===============================================================================
517 ===============================================================================
520 #define SAVEGAME_VERSION 5
522 void Host_Savegame_to (const char *name)
525 int i, lightstyles = 64;
526 char comment[SAVEGAME_COMMENT_LENGTH+1];
529 // first we have to figure out if this can be saved in 64 lightstyles
530 // (for Quake compatibility)
531 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
532 if (sv.lightstyles[i][0])
535 isserver = !strcmp(PRVM_NAME, "server");
537 Con_Printf("Saving game to %s...\n", name);
538 f = FS_OpenRealFile(name, "wb", false);
541 Con_Print("ERROR: couldn't open.\n");
545 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
547 memset(comment, 0, sizeof(comment));
549 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);
551 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
552 // convert space to _ to make stdio happy
553 // LordHavoc: convert control characters to _ as well
554 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
555 if (ISWHITESPACEORCONTROL(comment[i]))
557 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
559 FS_Printf(f, "%s\n", comment);
562 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
563 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
564 FS_Printf(f, "%d\n", current_skill);
565 FS_Printf(f, "%s\n", sv.name);
566 FS_Printf(f, "%f\n",sv.time);
570 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
571 FS_Printf(f, "(dummy)\n");
572 FS_Printf(f, "%d\n", 0);
573 FS_Printf(f, "%s\n", "(dummy)");
574 FS_Printf(f, "%f\n", realtime);
577 // write the light styles
578 for (i=0 ; i<lightstyles ; i++)
580 if (isserver && sv.lightstyles[i][0])
581 FS_Printf(f, "%s\n", sv.lightstyles[i]);
586 PRVM_ED_WriteGlobals (f);
587 for (i=0 ; i<prog->num_edicts ; i++)
589 FS_Printf(f,"// edict %d\n", i);
590 //Con_Printf("edict %d...\n", i);
591 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
596 FS_Printf(f,"// DarkPlaces extended savegame\n");
597 // darkplaces extension - extra lightstyles, support for color lightstyles
598 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
599 if (isserver && sv.lightstyles[i][0])
600 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
602 // darkplaces extension - model precaches
603 for (i=1 ; i<MAX_MODELS ; i++)
604 if (sv.model_precache[i][0])
605 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
607 // darkplaces extension - sound precaches
608 for (i=1 ; i<MAX_SOUNDS ; i++)
609 if (sv.sound_precache[i][0])
610 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
615 Con_Print("done.\n");
623 void Host_Savegame_f (void)
625 char name[MAX_QPATH];
629 Con_Print("Can't save - no server running.\n");
635 // singleplayer checks
638 Con_Print("Can't save in intermission.\n");
642 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
644 Con_Print("Can't savegame with a dead player\n");
649 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");
653 Con_Print("save <savename> : save a game\n");
657 if (strstr(Cmd_Argv(1), ".."))
659 Con_Print("Relative pathnames are not allowed.\n");
663 strlcpy (name, Cmd_Argv(1), sizeof (name));
664 FS_DefaultExtension (name, ".sav", sizeof (name));
667 Host_Savegame_to(name);
677 void Host_Loadgame_f (void)
679 char filename[MAX_QPATH];
680 char mapname[MAX_QPATH];
690 float spawn_parms[NUM_SPAWN_PARMS];
694 Con_Print("load <savename> : load a game\n");
698 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
699 FS_DefaultExtension (filename, ".sav", sizeof (filename));
701 Con_Printf("Loading game from %s...\n", filename);
703 // stop playing demos
704 if (cls.demoplayback)
710 cls.demonum = -1; // stop demo loop in case this fails
712 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
715 Con_Print("ERROR: couldn't open.\n");
719 if(developer_entityparsing.integer)
720 Con_Printf("Host_Loadgame_f: loading version\n");
723 COM_ParseToken_Simple(&t, false, false);
724 version = atoi(com_token);
725 if (version != SAVEGAME_VERSION)
728 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
732 if(developer_entityparsing.integer)
733 Con_Printf("Host_Loadgame_f: loading description\n");
736 COM_ParseToken_Simple(&t, false, false);
738 for (i = 0;i < NUM_SPAWN_PARMS;i++)
740 COM_ParseToken_Simple(&t, false, false);
741 spawn_parms[i] = atof(com_token);
744 COM_ParseToken_Simple(&t, false, false);
745 // this silliness is so we can load 1.06 save files, which have float skill values
746 current_skill = (int)(atof(com_token) + 0.5);
747 Cvar_SetValue ("skill", (float)current_skill);
749 if(developer_entityparsing.integer)
750 Con_Printf("Host_Loadgame_f: loading mapname\n");
753 COM_ParseToken_Simple(&t, false, false);
754 strlcpy (mapname, com_token, sizeof(mapname));
756 if(developer_entityparsing.integer)
757 Con_Printf("Host_Loadgame_f: loading time\n");
760 COM_ParseToken_Simple(&t, false, false);
761 time = atof(com_token);
763 allowcheats = sv_cheats.integer != 0;
765 if(developer_entityparsing.integer)
766 Con_Printf("Host_Loadgame_f: spawning server\n");
768 SV_SpawnServer (mapname);
772 Con_Print("Couldn't load map\n");
775 sv.paused = true; // pause until all clients connect
778 if(developer_entityparsing.integer)
779 Con_Printf("Host_Loadgame_f: loading light styles\n");
781 // load the light styles
787 for (i = 0;i < MAX_LIGHTSTYLES;i++)
791 COM_ParseToken_Simple(&t, false, false);
792 // if this is a 64 lightstyle savegame produced by Quake, stop now
793 // we have to check this because darkplaces may save more than 64
794 if (com_token[0] == '{')
799 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
802 if(developer_entityparsing.integer)
803 Con_Printf("Host_Loadgame_f: skipping until globals\n");
805 // now skip everything before the first opening brace
806 // (this is for forward compatibility, so that older versions (at
807 // least ones with this fix) can load savegames with extra data before the
808 // first brace, as might be produced by a later engine version)
812 if (!COM_ParseToken_Simple(&t, false, false))
814 if (com_token[0] == '{')
821 // load the edicts out of the savegame file
826 while (COM_ParseToken_Simple(&t, false, false))
827 if (!strcmp(com_token, "}"))
829 if (!COM_ParseToken_Simple(&start, false, false))
834 if (strcmp(com_token,"{"))
837 Host_Error ("First token isn't a brace");
842 if(developer_entityparsing.integer)
843 Con_Printf("Host_Loadgame_f: loading globals\n");
845 // parse the global vars
846 PRVM_ED_ParseGlobals (start);
851 if (entnum >= MAX_EDICTS)
854 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
856 while (entnum >= prog->max_edicts)
857 PRVM_MEM_IncreaseEdicts();
858 ent = PRVM_EDICT_NUM(entnum);
859 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
860 ent->priv.server->free = false;
862 if(developer_entityparsing.integer)
863 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
865 PRVM_ED_ParseEdict (start, ent);
867 // link it into the bsp tree
868 if (!ent->priv.server->free)
869 SV_LinkEdict (ent, false);
876 prog->num_edicts = entnum;
879 for (i = 0;i < NUM_SPAWN_PARMS;i++)
880 svs.clients[0].spawn_parms[i] = spawn_parms[i];
882 if(developer_entityparsing.integer)
883 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
885 // read extended data if present
886 // the extended data is stored inside a /* */ comment block, which the
887 // parser intentionally skips, so we have to check for it manually here
890 while (*end == '\r' || *end == '\n')
892 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
894 if(developer_entityparsing.integer)
895 Con_Printf("Host_Loadgame_f: loading extended data\n");
897 Con_Printf("Loading extended DarkPlaces savegame\n");
899 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
900 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
901 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
902 while (COM_ParseToken_Simple(&t, false, false))
904 if (!strcmp(com_token, "sv.lightstyles"))
906 COM_ParseToken_Simple(&t, false, false);
908 COM_ParseToken_Simple(&t, false, false);
909 if (i >= 0 && i < MAX_LIGHTSTYLES)
910 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
912 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
914 else if (!strcmp(com_token, "sv.model_precache"))
916 COM_ParseToken_Simple(&t, false, false);
918 COM_ParseToken_Simple(&t, false, false);
919 if (i >= 0 && i < MAX_MODELS)
921 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
922 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
925 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
927 else if (!strcmp(com_token, "sv.sound_precache"))
929 COM_ParseToken_Simple(&t, false, false);
931 COM_ParseToken_Simple(&t, false, false);
932 if (i >= 0 && i < MAX_SOUNDS)
933 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
935 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
937 // skip any trailing text or unrecognized commands
938 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
945 if(developer_entityparsing.integer)
946 Con_Printf("Host_Loadgame_f: finished\n");
950 // make sure we're connected to loopback
951 if (sv.active && cls.state == ca_disconnected)
952 CL_EstablishConnection("local:1");
955 //============================================================================
958 ======================
960 ======================
962 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
963 void Host_Name_f (void)
966 qboolean valid_colors;
967 char newName[sizeof(host_client->name)];
969 if (Cmd_Argc () == 1)
971 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
975 if (Cmd_Argc () == 2)
976 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
978 strlcpy (newName, Cmd_Args(), sizeof (newName));
980 if (cmd_source == src_command)
982 Cvar_Set ("_cl_name", newName);
986 if (realtime < host_client->nametime)
988 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
992 host_client->nametime = realtime + 5;
994 // point the string back at updateclient->name to keep it safe
995 strlcpy (host_client->name, newName, sizeof (host_client->name));
997 for (i = 0, j = 0;host_client->name[i];i++)
998 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
999 host_client->name[j++] = host_client->name[i];
1000 host_client->name[j] = 0;
1002 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1003 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1005 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1006 host_client->name[sizeof(host_client->name) - 1] = 0;
1007 host_client->name[0] = STRING_COLOR_TAG;
1008 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1011 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1012 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1015 l = strlen(host_client->name);
1016 if(l < sizeof(host_client->name) - 1)
1018 // duplicate the color tag to escape it
1019 host_client->name[i] = STRING_COLOR_TAG;
1020 host_client->name[i+1] = 0;
1021 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1025 // remove the last character to fix the color code
1026 host_client->name[l-1] = 0;
1027 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1031 // find the last color tag offset and decide if we need to add a reset tag
1032 for (i = 0, j = -1;host_client->name[i];i++)
1034 if (host_client->name[i] == STRING_COLOR_TAG)
1036 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1039 // if this happens to be a reset tag then we don't need one
1040 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1045 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]))
1051 if (host_client->name[i+1] == STRING_COLOR_TAG)
1058 // does not end in the default color string, so add it
1059 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1060 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1062 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1063 if (strcmp(host_client->old_name, host_client->name))
1065 if (host_client->spawned)
1066 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1067 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1068 // send notification to all clients
1069 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1070 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1071 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1072 SV_WriteNetnameIntoDemo(host_client);
1077 ======================
1079 ======================
1081 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1082 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1083 void Host_Playermodel_f (void)
1086 char newPath[sizeof(host_client->playermodel)];
1088 if (Cmd_Argc () == 1)
1090 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1094 if (Cmd_Argc () == 2)
1095 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1097 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1099 for (i = 0, j = 0;newPath[i];i++)
1100 if (newPath[i] != '\r' && newPath[i] != '\n')
1101 newPath[j++] = newPath[i];
1104 if (cmd_source == src_command)
1106 Cvar_Set ("_cl_playermodel", newPath);
1111 if (realtime < host_client->nametime)
1113 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1117 host_client->nametime = realtime + 5;
1120 // point the string back at updateclient->name to keep it safe
1121 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1122 if( prog->fieldoffsets.playermodel >= 0 )
1123 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1124 if (strcmp(host_client->old_model, host_client->playermodel))
1126 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1127 /*// send notification to all clients
1128 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1129 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1130 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1135 ======================
1137 ======================
1139 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1140 void Host_Playerskin_f (void)
1143 char newPath[sizeof(host_client->playerskin)];
1145 if (Cmd_Argc () == 1)
1147 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1151 if (Cmd_Argc () == 2)
1152 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1154 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1156 for (i = 0, j = 0;newPath[i];i++)
1157 if (newPath[i] != '\r' && newPath[i] != '\n')
1158 newPath[j++] = newPath[i];
1161 if (cmd_source == src_command)
1163 Cvar_Set ("_cl_playerskin", newPath);
1168 if (realtime < host_client->nametime)
1170 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1174 host_client->nametime = realtime + 5;
1177 // point the string back at updateclient->name to keep it safe
1178 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1179 if( prog->fieldoffsets.playerskin >= 0 )
1180 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1181 if (strcmp(host_client->old_skin, host_client->playerskin))
1183 //if (host_client->spawned)
1184 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1185 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1186 /*// send notification to all clients
1187 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1188 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1189 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1193 void Host_Version_f (void)
1195 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1198 void Host_Say(qboolean teamonly)
1204 // LordHavoc: long say messages
1206 qboolean fromServer = false;
1208 if (cmd_source == src_command)
1210 if (cls.state == ca_dedicated)
1217 Cmd_ForwardToServer ();
1222 if (Cmd_Argc () < 2)
1225 if (!teamplay.integer)
1235 // note this uses the chat prefix \001
1236 if (!fromServer && !teamonly)
1237 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1238 else if (!fromServer && teamonly)
1239 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1240 else if(*(sv_adminnick.string))
1241 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1243 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1244 p2 = text + strlen(text);
1245 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1247 if (p2[-1] == '\"' && quoted)
1252 strlcat(text, "\n", sizeof(text));
1254 // note: save is not a valid edict if fromServer is true
1256 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1257 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1258 SV_ClientPrint(text);
1261 if (cls.state == ca_dedicated)
1262 Con_Print(&text[1]);
1266 void Host_Say_f(void)
1272 void Host_Say_Team_f(void)
1278 void Host_Tell_f(void)
1280 const char *playername_start = NULL;
1281 size_t playername_length = 0;
1282 int playernumber = 0;
1285 const char *p1, *p2;
1286 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1287 qboolean fromServer = false;
1289 if (cmd_source == src_command)
1291 if (cls.state == ca_dedicated)
1295 Cmd_ForwardToServer ();
1300 if (Cmd_Argc () < 2)
1303 // note this uses the chat prefix \001
1305 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1306 else if(*(sv_adminnick.string))
1307 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1309 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1312 p2 = p1 + strlen(p1);
1313 // remove the target name
1314 while (p1 < p2 && *p1 == ' ')
1319 while (p1 < p2 && *p1 == ' ')
1321 while (p1 < p2 && isdigit(*p1))
1323 playernumber = playernumber * 10 + (*p1 - '0');
1331 playername_start = p1;
1332 while (p1 < p2 && *p1 != '"')
1334 playername_length = p1 - playername_start;
1340 playername_start = p1;
1341 while (p1 < p2 && *p1 != ' ')
1343 playername_length = p1 - playername_start;
1345 while (p1 < p2 && *p1 == ' ')
1347 if(playername_start)
1349 // set playernumber to the right client
1351 if(playername_length >= sizeof(namebuf))
1354 Con_Print("Host_Tell: too long player name/ID\n");
1356 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1359 memcpy(namebuf, playername_start, playername_length);
1360 namebuf[playername_length] = 0;
1361 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1363 if (!svs.clients[playernumber].active)
1365 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1369 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1372 Con_Print("Host_Tell: invalid player name/ID\n");
1374 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1377 // remove trailing newlines
1378 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1380 // remove quotes if present
1386 else if (fromServer)
1387 Con_Print("Host_Tell: missing end quote\n");
1389 SV_ClientPrint("Host_Tell: missing end quote\n");
1391 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1394 return; // empty say
1395 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1401 host_client = svs.clients + playernumber;
1402 SV_ClientPrint(text);
1412 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1413 void Host_Color(int changetop, int changebottom)
1415 int top, bottom, playercolor;
1417 // get top and bottom either from the provided values or the current values
1418 // (allows changing only top or bottom, or both at once)
1419 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1420 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1424 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1430 playercolor = top*16 + bottom;
1432 if (cmd_source == src_command)
1434 Cvar_SetValueQuick(&cl_color, playercolor);
1438 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1441 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1443 Con_DPrint("Calling SV_ChangeTeam\n");
1444 prog->globals.server->time = sv.time;
1445 prog->globals.generic[OFS_PARM0] = playercolor;
1446 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1447 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1452 if (host_client->edict)
1454 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1455 val->_float = playercolor;
1456 host_client->edict->fields.server->team = bottom + 1;
1458 host_client->colors = playercolor;
1459 if (host_client->old_colors != host_client->colors)
1461 host_client->old_colors = host_client->colors;
1462 // send notification to all clients
1463 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1464 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1465 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1470 void Host_Color_f(void)
1474 if (Cmd_Argc() == 1)
1476 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1477 Con_Print("color <0-15> [0-15]\n");
1481 if (Cmd_Argc() == 2)
1482 top = bottom = atoi(Cmd_Argv(1));
1485 top = atoi(Cmd_Argv(1));
1486 bottom = atoi(Cmd_Argv(2));
1488 Host_Color(top, bottom);
1491 void Host_TopColor_f(void)
1493 if (Cmd_Argc() == 1)
1495 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1496 Con_Print("topcolor <0-15>\n");
1500 Host_Color(atoi(Cmd_Argv(1)), -1);
1503 void Host_BottomColor_f(void)
1505 if (Cmd_Argc() == 1)
1507 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1508 Con_Print("bottomcolor <0-15>\n");
1512 Host_Color(-1, atoi(Cmd_Argv(1)));
1515 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1516 void Host_Rate_f(void)
1520 if (Cmd_Argc() != 2)
1522 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1523 Con_Print("rate <bytespersecond>\n");
1527 rate = atoi(Cmd_Argv(1));
1529 if (cmd_source == src_command)
1531 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1535 host_client->rate = rate;
1543 void Host_Kill_f (void)
1545 if (host_client->edict->fields.server->health <= 0)
1547 SV_ClientPrint("Can't suicide -- already dead!\n");
1551 prog->globals.server->time = sv.time;
1552 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1553 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1562 void Host_Pause_f (void)
1564 if (!pausable.integer)
1565 SV_ClientPrint("Pause not allowed.\n");
1569 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1570 // send notification to all clients
1571 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1572 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1577 ======================
1579 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1580 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1581 ======================
1583 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)"};
1584 static void Host_PModel_f (void)
1589 if (Cmd_Argc () == 1)
1591 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1594 i = atoi(Cmd_Argv(1));
1596 if (cmd_source == src_command)
1598 if (cl_pmodel.integer == i)
1600 Cvar_SetValue ("_cl_pmodel", i);
1601 if (cls.state == ca_connected)
1602 Cmd_ForwardToServer ();
1606 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1610 //===========================================================================
1618 void Host_PreSpawn_f (void)
1620 if (host_client->spawned)
1622 Con_Print("prespawn not valid -- already spawned\n");
1626 if (host_client->netconnection)
1628 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1629 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1630 MSG_WriteByte (&host_client->netconnection->message, 2);
1631 host_client->sendsignon = 0; // enable unlimited sends again
1634 // reset the name change timer because the client will send name soon
1635 host_client->nametime = 0;
1643 void Host_Spawn_f (void)
1647 int stats[MAX_CL_STATS];
1649 if (host_client->spawned)
1651 Con_Print("Spawn not valid -- already spawned\n");
1655 // reset name change timer again because they might want to change name
1656 // again in the first 5 seconds after connecting
1657 host_client->nametime = 0;
1659 // LordHavoc: moved this above the QC calls at FrikaC's request
1660 // LordHavoc: commented this out
1661 //if (host_client->netconnection)
1662 // SZ_Clear (&host_client->netconnection->message);
1664 // run the entrance script
1667 // loaded games are fully initialized already
1668 if (prog->funcoffsets.RestoreGame)
1670 Con_DPrint("Calling RestoreGame\n");
1671 prog->globals.server->time = sv.time;
1672 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1673 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1678 //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);
1680 // copy spawn parms out of the client_t
1681 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1682 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1684 // call the spawn function
1685 host_client->clientconnectcalled = true;
1686 prog->globals.server->time = sv.time;
1687 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1688 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1690 if (cls.state == ca_dedicated)
1691 Con_Printf("%s connected\n", host_client->name);
1693 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1696 if (!host_client->netconnection)
1699 // send time of update
1700 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1701 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1703 // send all current names, colors, and frag counts
1704 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1706 if (!client->active)
1708 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1709 MSG_WriteByte (&host_client->netconnection->message, i);
1710 MSG_WriteString (&host_client->netconnection->message, client->name);
1711 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1712 MSG_WriteByte (&host_client->netconnection->message, i);
1713 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1714 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1715 MSG_WriteByte (&host_client->netconnection->message, i);
1716 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1719 // send all current light styles
1720 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1722 if (sv.lightstyles[i][0])
1724 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1725 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1726 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1731 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1732 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1733 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1735 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1736 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1737 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1739 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1740 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1741 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1743 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1744 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1745 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1748 // Never send a roll angle, because savegames can catch the server
1749 // in a state where it is expecting the client to correct the angle
1750 // and it won't happen if the game was just loaded, so you wind up
1751 // with a permanent head tilt
1754 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1755 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1756 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1757 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1761 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1762 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1763 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1764 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1767 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1769 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1770 MSG_WriteByte (&host_client->netconnection->message, 3);
1778 void Host_Begin_f (void)
1780 host_client->spawned = true;
1782 // LordHavoc: note: this code also exists in SV_DropClient
1786 for (i = 0;i < svs.maxclients;i++)
1787 if (svs.clients[i].active && !svs.clients[i].spawned)
1789 if (i == svs.maxclients)
1791 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1792 sv.paused = sv.loadgame = false; // we're basically done with loading now
1797 //===========================================================================
1804 Kicks a user off of the server
1807 void Host_Kick_f (void)
1810 const char *message = NULL;
1813 qboolean byNumber = false;
1821 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1823 i = (int)(atof(Cmd_Argv(2)) - 1);
1824 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1830 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1832 if (!host_client->active)
1834 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1839 if (i < svs.maxclients)
1841 if (cmd_source == src_command)
1843 if (cls.state == ca_dedicated)
1846 who = cl_name.string;
1851 // can't kick yourself!
1852 if (host_client == save)
1857 message = Cmd_Args();
1858 COM_ParseToken_Simple(&message, false, false);
1861 message++; // skip the #
1862 while (*message == ' ') // skip white space
1864 message += strlen(Cmd_Argv(2)); // skip the number
1866 while (*message && *message == ' ')
1870 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1872 SV_ClientPrintf("Kicked by %s\n", who);
1873 SV_DropClient (false); // kicked
1881 ===============================================================================
1885 ===============================================================================
1893 void Host_Give_f (void)
1901 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1906 v = atoi (Cmd_Argv(2));
1920 // MED 01/04/97 added hipnotic give stuff
1921 if (gamemode == GAME_HIPNOTIC)
1926 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1928 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1930 else if (t[0] == '9')
1931 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1932 else if (t[0] == '0')
1933 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1934 else if (t[0] >= '2')
1935 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1940 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1945 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1948 host_client->edict->fields.server->ammo_shells = v;
1951 if (gamemode == GAME_ROGUE)
1953 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1956 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1957 host_client->edict->fields.server->ammo_nails = v;
1962 host_client->edict->fields.server->ammo_nails = v;
1966 if (gamemode == GAME_ROGUE)
1968 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1972 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1973 host_client->edict->fields.server->ammo_nails = v;
1978 if (gamemode == GAME_ROGUE)
1980 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
1984 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1985 host_client->edict->fields.server->ammo_rockets = v;
1990 host_client->edict->fields.server->ammo_rockets = v;
1994 if (gamemode == GAME_ROGUE)
1996 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2000 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2001 host_client->edict->fields.server->ammo_rockets = v;
2006 host_client->edict->fields.server->health = v;
2009 if (gamemode == GAME_ROGUE)
2011 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2015 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2016 host_client->edict->fields.server->ammo_cells = v;
2021 host_client->edict->fields.server->ammo_cells = v;
2025 if (gamemode == GAME_ROGUE)
2027 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2031 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2032 host_client->edict->fields.server->ammo_cells = v;
2039 prvm_edict_t *FindViewthing (void)
2044 for (i=0 ; i<prog->num_edicts ; i++)
2046 e = PRVM_EDICT_NUM(i);
2047 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2050 Con_Print("No viewthing on map\n");
2059 void Host_Viewmodel_f (void)
2068 e = FindViewthing ();
2073 m = Mod_ForName (Cmd_Argv(1), false, true, false);
2074 if (!m || !m->loaded || !m->Draw)
2076 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2080 e->fields.server->frame = 0;
2081 cl.model_precache[(int)e->fields.server->modelindex] = m;
2089 void Host_Viewframe_f (void)
2099 e = FindViewthing ();
2103 m = cl.model_precache[(int)e->fields.server->modelindex];
2105 f = atoi(Cmd_Argv(1));
2106 if (f >= m->numframes)
2109 e->fields.server->frame = f;
2113 void PrintFrameName (dp_model_t *m, int frame)
2116 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2118 Con_Printf("frame %i\n", frame);
2126 void Host_Viewnext_f (void)
2135 e = FindViewthing ();
2139 m = cl.model_precache[(int)e->fields.server->modelindex];
2141 e->fields.server->frame = e->fields.server->frame + 1;
2142 if (e->fields.server->frame >= m->numframes)
2143 e->fields.server->frame = m->numframes - 1;
2145 PrintFrameName (m, (int)e->fields.server->frame);
2153 void Host_Viewprev_f (void)
2162 e = FindViewthing ();
2167 m = cl.model_precache[(int)e->fields.server->modelindex];
2169 e->fields.server->frame = e->fields.server->frame - 1;
2170 if (e->fields.server->frame < 0)
2171 e->fields.server->frame = 0;
2173 PrintFrameName (m, (int)e->fields.server->frame);
2177 ===============================================================================
2181 ===============================================================================
2190 void Host_Startdemos_f (void)
2194 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2200 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2203 Con_DPrintf("%i demo(s) in loop\n", c);
2205 for (i=1 ; i<c+1 ; i++)
2206 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2208 // LordHavoc: clear the remaining slots
2209 for (;i <= MAX_DEMOS;i++)
2210 cls.demos[i-1][0] = 0;
2212 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2226 Return to looping demos
2229 void Host_Demos_f (void)
2231 if (cls.state == ca_dedicated)
2233 if (cls.demonum == -1)
2243 Return to looping demos
2246 void Host_Stopdemo_f (void)
2248 if (!cls.demoplayback)
2251 Host_ShutdownServer ();
2254 void Host_SendCvar_f (void)
2258 const char *cvarname;
2263 cvarname = Cmd_Argv(1);
2264 if (cls.state == ca_connected)
2266 c = Cvar_FindVar(cvarname);
2267 // LordHavoc: if there is no such cvar or if it is private, send a
2268 // reply indicating that it has no value
2269 if(!c || (c->flags & CVAR_PRIVATE))
2270 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2272 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2275 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2279 if (cls.state != ca_dedicated)
2283 for(;i<svs.maxclients;i++)
2284 if(svs.clients[i].active && svs.clients[i].netconnection)
2286 host_client = &svs.clients[i];
2287 Host_ClientCommands("sendcvar %s\n", cvarname);
2292 static void MaxPlayers_f(void)
2296 if (Cmd_Argc() != 2)
2298 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
2304 Con_Print("maxplayers can not be changed while a server is running.\n");
2308 n = atoi(Cmd_Argv(1));
2309 n = bound(1, n, MAX_SCOREBOARD);
2310 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2313 Mem_Free(svs.clients);
2315 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
2317 Cvar_Set ("deathmatch", "0");
2319 Cvar_Set ("deathmatch", "1");
2322 //=============================================================================
2324 // QuakeWorld commands
2327 =====================
2330 Send the rest of the command line over as
2331 an unconnected command.
2332 =====================
2334 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2338 lhnetsocket_t *mysocket;
2340 if (!rcon_password.string || !rcon_password.string[0])
2342 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2346 for (i = 0;rcon_password.string[i];i++)
2348 if (ISWHITESPACE(rcon_password.string[i]))
2350 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2356 to = cls.netcon->peeraddress;
2359 if (!rcon_address.string[0])
2361 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2364 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2366 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2369 // simply put together the rcon packet and send it
2370 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2375 ====================
2378 user <name or userid>
2380 Dump userdata / masterdata for a user
2381 ====================
2383 void Host_User_f (void) // credit: taken from QuakeWorld
2388 if (Cmd_Argc() != 2)
2390 Con_Printf ("Usage: user <username / userid>\n");
2394 uid = atoi(Cmd_Argv(1));
2396 for (i = 0;i < cl.maxclients;i++)
2398 if (!cl.scores[i].name[0])
2400 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2402 InfoString_Print(cl.scores[i].qw_userinfo);
2406 Con_Printf ("User not in server.\n");
2410 ====================
2413 Dump userids for all current players
2414 ====================
2416 void Host_Users_f (void) // credit: taken from QuakeWorld
2422 Con_Printf ("userid frags name\n");
2423 Con_Printf ("------ ----- ----\n");
2424 for (i = 0;i < cl.maxclients;i++)
2426 if (cl.scores[i].name[0])
2428 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2433 Con_Printf ("%i total users\n", c);
2438 Host_FullServerinfo_f
2440 Sent by server when serverinfo changes
2443 // TODO: shouldn't this be a cvar instead?
2444 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2447 if (Cmd_Argc() != 2)
2449 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2453 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2454 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2455 cl.qw_teamplay = atoi(temp);
2462 Allow clients to change userinfo
2466 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2473 if (Cmd_Argc() != 2)
2475 Con_Printf ("fullinfo <complete info string>\n");
2485 while (*s && *s != '\\')
2491 Con_Printf ("MISSING VALUE\n");
2497 while (*s && *s != '\\')
2504 CL_SetInfo(key, value, false, false, false, false);
2512 Allow clients to change userinfo
2515 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2517 if (Cmd_Argc() == 1)
2519 InfoString_Print(cls.userinfo);
2522 if (Cmd_Argc() != 3)
2524 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2527 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2531 ====================
2534 packet <destination> <contents>
2536 Contents allows \n escape character
2537 ====================
2539 void Host_Packet_f (void) // credit: taken from QuakeWorld
2545 lhnetaddress_t address;
2546 lhnetsocket_t *mysocket;
2548 if (Cmd_Argc() != 3)
2550 Con_Printf ("packet <destination> <contents>\n");
2554 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2556 Con_Printf ("Bad address\n");
2562 send[0] = send[1] = send[2] = send[3] = 0xff;
2564 l = (int)strlen (in);
2565 for (i=0 ; i<l ; i++)
2567 if (out >= send + sizeof(send) - 1)
2569 if (in[i] == '\\' && in[i+1] == 'n')
2574 else if (in[i] == '\\' && in[i+1] == '0')
2579 else if (in[i] == '\\' && in[i+1] == 't')
2584 else if (in[i] == '\\' && in[i+1] == 'r')
2589 else if (in[i] == '\\' && in[i+1] == '"')
2598 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2600 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2602 NetConn_Write(mysocket, send, out - send, &address);
2606 ====================
2609 Send back ping and packet loss update for all current players to this player
2610 ====================
2612 void Host_Pings_f (void)
2614 int i, j, ping, packetloss;
2617 if (!host_client->netconnection)
2620 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2622 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2623 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2625 for (i = 0;i < svs.maxclients;i++)
2628 if (svs.clients[i].netconnection)
2629 for (j = 0;j < NETGRAPH_PACKETS;j++)
2630 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2632 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2633 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2634 ping = bound(0, ping, 9999);
2635 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2637 // send qw_svc_updateping and qw_svc_updatepl messages
2638 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2639 MSG_WriteShort(&host_client->netconnection->message, ping);
2640 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2641 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2645 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2646 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2647 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2650 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2651 MSG_WriteString(&host_client->netconnection->message, "\n");
2654 void Host_PingPLReport_f(void)
2658 if (l > cl.maxclients)
2660 for (i = 0;i < l;i++)
2662 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2663 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2667 //=============================================================================
2674 void Host_InitCommands (void)
2676 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2678 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2679 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2680 if (gamemode == GAME_NEHAHRA)
2682 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2683 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2684 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2685 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2686 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2690 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2691 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2692 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2693 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2694 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2696 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2697 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2698 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2699 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2700 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)");
2701 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2702 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2703 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2704 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2705 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2706 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2707 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2708 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2709 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2710 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2712 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2713 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2714 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2716 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2717 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2718 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2719 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2721 Cvar_RegisterVariable (&cl_name);
2722 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2723 Cvar_RegisterVariable (&cl_color);
2724 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2725 Cvar_RegisterVariable (&cl_rate);
2726 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2727 if (gamemode == GAME_NEHAHRA)
2729 Cvar_RegisterVariable (&cl_pmodel);
2730 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2733 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2734 Cvar_RegisterVariable (&cl_playermodel);
2735 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2736 Cvar_RegisterVariable (&cl_playerskin);
2737 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2739 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2740 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2741 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)");
2742 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2744 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2746 Cvar_RegisterVariable (&rcon_password);
2747 Cvar_RegisterVariable (&rcon_address);
2748 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)");
2749 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2750 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2751 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2752 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2753 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2754 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2755 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2756 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2758 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)");
2759 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)");
2761 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)");
2762 Cvar_RegisterVariable (&r_fixtrans_auto);
2764 Cvar_RegisterVariable (&team);
2765 Cvar_RegisterVariable (&skin);
2766 Cvar_RegisterVariable (&noaim);
2768 Cvar_RegisterVariable(&sv_cheats);
2769 Cvar_RegisterVariable(&sv_adminnick);
2770 Cvar_RegisterVariable(&sv_status_privacy);
2771 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2774 void Host_NoOperation_f(void)