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, ...);
70 if (cmd_source == src_command)
72 // if running a client, try to send over network so the client's status report parser will see the report
73 if (cls.state == ca_connected)
75 Cmd_ForwardToServer ();
81 print = SV_ClientPrintf;
94 if (strcmp(Cmd_Argv(1), "1") == 0)
96 else if (strcmp(Cmd_Argv(1), "2") == 0)
100 for (players = 0, i = 0;i < svs.maxclients;i++)
101 if (svs.clients[i].active)
103 print ("host: %s\n", Cvar_VariableString ("hostname"));
104 print ("version: %s build %s\n", gamename, buildstring);
105 print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
106 print ("map: %s\n", sv.name);
107 print ("timing: %s\n", Host_TimingReport());
108 print ("players: %i active (%i max)\n\n", players, svs.maxclients);
111 print ("^2IP %%pl ping time frags no name\n");
113 print ("^5IP no name\n");
115 for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
122 if (in == 0 || in == 1)
124 seconds = (int)(realtime - client->connecttime);
125 minutes = seconds / 60;
128 seconds -= (minutes * 60);
129 hours = minutes / 60;
131 minutes -= (hours * 60);
137 if (client->netconnection)
138 for (j = 0;j < NETGRAPH_PACKETS;j++)
139 if (client->netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
141 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
142 ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
145 if(sv_status_privacy.integer && cmd_source != src_command)
146 strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
148 strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
150 frags = client->frags;
152 if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
154 const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
160 for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
161 if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
165 frags = atoi(qcstatus);
169 if (in == 0) // default layout
171 print ("#%-3u ", i+1);
172 print ("%-16.16s ", client->name);
173 print ("%4i ", frags);
174 print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
177 else if (in == 1) // extended layout
179 k%2 ? print("^3") : print("^7");
180 print ("%-21s ", ip);
181 print ("%2i ", packetloss);
182 print ("%4i ", ping);
183 print ("%2i:%02i:%02i ", hours, minutes, seconds);
184 print ("%4i ", frags);
185 print ("#%-3u ", i+1);
186 print ("^7%s\n", client->name);
188 else if (in == 2) // reduced layout
190 k%2 ? print("^3") : print("^7");
191 print ("%-21s ", ip);
192 print ("#%-3u ", i+1);
193 print ("^7%s\n", client->name);
207 Sets client to godmode
210 void Host_God_f (void)
214 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
218 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
219 if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
220 SV_ClientPrint("godmode OFF\n");
222 SV_ClientPrint("godmode ON\n");
225 void Host_Notarget_f (void)
229 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
233 host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
234 if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
235 SV_ClientPrint("notarget OFF\n");
237 SV_ClientPrint("notarget ON\n");
240 qboolean noclip_anglehack;
242 void Host_Noclip_f (void)
246 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
250 if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
252 noclip_anglehack = true;
253 host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
254 SV_ClientPrint("noclip ON\n");
258 noclip_anglehack = false;
259 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
260 SV_ClientPrint("noclip OFF\n");
268 Sets client to flymode
271 void Host_Fly_f (void)
275 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
279 if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
281 host_client->edict->fields.server->movetype = MOVETYPE_FLY;
282 SV_ClientPrint("flymode ON\n");
286 host_client->edict->fields.server->movetype = MOVETYPE_WALK;
287 SV_ClientPrint("flymode OFF\n");
298 void Host_Pings_f (void); // called by Host_Ping_f
299 void Host_Ping_f (void)
303 void (*print) (const char *fmt, ...);
305 if (cmd_source == src_command)
307 // if running a client, try to send over network so the client's ping report parser will see the report
308 if (cls.state == ca_connected)
310 Cmd_ForwardToServer ();
316 print = SV_ClientPrintf;
321 print("Client ping times:\n");
322 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
326 print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
329 // 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)
330 // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
335 ===============================================================================
339 ===============================================================================
343 ======================
348 command from the console. Active clients are kicked off.
349 ======================
351 void Host_Map_f (void)
353 char level[MAX_QPATH];
357 Con_Print("map <levelname> : start a new game (kicks off all players)\n");
361 // GAME_DELUXEQUAKE - clear warpmark (used by QC)
362 if (gamemode == GAME_DELUXEQUAKE)
363 Cvar_Set("warpmark", "");
365 cls.demonum = -1; // stop demo loop in case this fails
368 Host_ShutdownServer();
373 svs.serverflags = 0; // haven't completed an episode yet
374 allowcheats = sv_cheats.integer != 0;
375 strlcpy(level, Cmd_Argv(1), sizeof(level));
376 SV_SpawnServer(level);
377 if (sv.active && cls.state == ca_disconnected)
378 CL_EstablishConnection("local:1");
385 Goes to a new map, taking all clients along
388 void Host_Changelevel_f (void)
390 char level[MAX_QPATH];
394 Con_Print("changelevel <levelname> : continue game on a new level\n");
407 SV_SaveSpawnparms ();
409 allowcheats = sv_cheats.integer != 0;
410 strlcpy(level, Cmd_Argv(1), sizeof(level));
411 SV_SpawnServer(level);
412 if (sv.active && cls.state == ca_disconnected)
413 CL_EstablishConnection("local:1");
420 Restarts the current server for a dead player
423 void Host_Restart_f (void)
425 char mapname[MAX_QPATH];
429 Con_Print("restart : restart current level\n");
434 Con_Print("Only the server may restart\n");
441 allowcheats = sv_cheats.integer != 0;
442 strlcpy(mapname, sv.name, sizeof(mapname));
443 SV_SpawnServer(mapname);
444 if (sv.active && cls.state == ca_disconnected)
445 CL_EstablishConnection("local:1");
452 This command causes the client to wait for the signon messages again.
453 This is sent just before a server changes levels
456 void Host_Reconnect_f (void)
459 // if not connected, reconnect to the most recent server
462 // if we have connected to a server recently, the userinfo
463 // will still contain its IP address, so get the address...
464 InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp));
466 CL_EstablishConnection(temp);
468 Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n");
471 // if connected, do something based on protocol
472 if (cls.protocol == PROTOCOL_QUAKEWORLD)
474 // quakeworld can just re-login
475 if (cls.qw_downloadmemory) // don't change when downloading
480 if (cls.state == ca_connected && cls.signon < SIGNONS)
482 Con_Printf("reconnecting...\n");
483 MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
484 MSG_WriteString(&cls.netcon->message, "new");
489 // netquake uses reconnect on level changes (silly)
492 Con_Print("reconnect : wait for signon messages again\n");
497 Con_Print("reconnect: no signon, ignoring reconnect\n");
500 cls.signon = 0; // need new connection messages
505 =====================
508 User command to connect to server
509 =====================
511 void Host_Connect_f (void)
515 Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
518 CL_EstablishConnection(Cmd_Argv(1));
523 ===============================================================================
527 ===============================================================================
530 #define SAVEGAME_VERSION 5
532 void Host_Savegame_to (const char *name)
535 int i, lightstyles = 64;
536 char comment[SAVEGAME_COMMENT_LENGTH+1];
539 // first we have to figure out if this can be saved in 64 lightstyles
540 // (for Quake compatibility)
541 for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
542 if (sv.lightstyles[i][0])
545 isserver = !strcmp(PRVM_NAME, "server");
547 Con_Printf("Saving game to %s...\n", name);
548 f = FS_OpenRealFile(name, "wb", false);
551 Con_Print("ERROR: couldn't open.\n");
555 FS_Printf(f, "%i\n", SAVEGAME_VERSION);
557 memset(comment, 0, sizeof(comment));
559 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);
561 dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
562 // convert space to _ to make stdio happy
563 // LordHavoc: convert control characters to _ as well
564 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
565 if (ISWHITESPACEORCONTROL(comment[i]))
567 comment[SAVEGAME_COMMENT_LENGTH] = '\0';
569 FS_Printf(f, "%s\n", comment);
572 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
573 FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
574 FS_Printf(f, "%d\n", current_skill);
575 FS_Printf(f, "%s\n", sv.name);
576 FS_Printf(f, "%f\n",sv.time);
580 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
581 FS_Printf(f, "(dummy)\n");
582 FS_Printf(f, "%d\n", 0);
583 FS_Printf(f, "%s\n", "(dummy)");
584 FS_Printf(f, "%f\n", realtime);
587 // write the light styles
588 for (i=0 ; i<lightstyles ; i++)
590 if (isserver && sv.lightstyles[i][0])
591 FS_Printf(f, "%s\n", sv.lightstyles[i]);
596 PRVM_ED_WriteGlobals (f);
597 for (i=0 ; i<prog->num_edicts ; i++)
599 FS_Printf(f,"// edict %d\n", i);
600 //Con_Printf("edict %d...\n", i);
601 PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
606 FS_Printf(f,"// DarkPlaces extended savegame\n");
607 // darkplaces extension - extra lightstyles, support for color lightstyles
608 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
609 if (isserver && sv.lightstyles[i][0])
610 FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
612 // darkplaces extension - model precaches
613 for (i=1 ; i<MAX_MODELS ; i++)
614 if (sv.model_precache[i][0])
615 FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
617 // darkplaces extension - sound precaches
618 for (i=1 ; i<MAX_SOUNDS ; i++)
619 if (sv.sound_precache[i][0])
620 FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
625 Con_Print("done.\n");
633 void Host_Savegame_f (void)
635 char name[MAX_QPATH];
639 Con_Print("Can't save - no server running.\n");
645 // singleplayer checks
648 Con_Print("Can't save in intermission.\n");
652 if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
654 Con_Print("Can't savegame with a dead player\n");
659 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");
663 Con_Print("save <savename> : save a game\n");
667 if (strstr(Cmd_Argv(1), ".."))
669 Con_Print("Relative pathnames are not allowed.\n");
673 strlcpy (name, Cmd_Argv(1), sizeof (name));
674 FS_DefaultExtension (name, ".sav", sizeof (name));
677 Host_Savegame_to(name);
687 void Host_Loadgame_f (void)
689 char filename[MAX_QPATH];
690 char mapname[MAX_QPATH];
700 float spawn_parms[NUM_SPAWN_PARMS];
704 Con_Print("load <savename> : load a game\n");
708 strlcpy (filename, Cmd_Argv(1), sizeof(filename));
709 FS_DefaultExtension (filename, ".sav", sizeof (filename));
711 Con_Printf("Loading game from %s...\n", filename);
713 // stop playing demos
714 if (cls.demoplayback)
720 cls.demonum = -1; // stop demo loop in case this fails
722 t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
725 Con_Print("ERROR: couldn't open.\n");
729 if(developer_entityparsing.integer)
730 Con_Printf("Host_Loadgame_f: loading version\n");
733 COM_ParseToken_Simple(&t, false, false);
734 version = atoi(com_token);
735 if (version != SAVEGAME_VERSION)
738 Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
742 if(developer_entityparsing.integer)
743 Con_Printf("Host_Loadgame_f: loading description\n");
746 COM_ParseToken_Simple(&t, false, false);
748 for (i = 0;i < NUM_SPAWN_PARMS;i++)
750 COM_ParseToken_Simple(&t, false, false);
751 spawn_parms[i] = atof(com_token);
754 COM_ParseToken_Simple(&t, false, false);
755 // this silliness is so we can load 1.06 save files, which have float skill values
756 current_skill = (int)(atof(com_token) + 0.5);
757 Cvar_SetValue ("skill", (float)current_skill);
759 if(developer_entityparsing.integer)
760 Con_Printf("Host_Loadgame_f: loading mapname\n");
763 COM_ParseToken_Simple(&t, false, false);
764 strlcpy (mapname, com_token, sizeof(mapname));
766 if(developer_entityparsing.integer)
767 Con_Printf("Host_Loadgame_f: loading time\n");
770 COM_ParseToken_Simple(&t, false, false);
771 time = atof(com_token);
773 allowcheats = sv_cheats.integer != 0;
775 if(developer_entityparsing.integer)
776 Con_Printf("Host_Loadgame_f: spawning server\n");
778 SV_SpawnServer (mapname);
782 Con_Print("Couldn't load map\n");
785 sv.paused = true; // pause until all clients connect
788 if(developer_entityparsing.integer)
789 Con_Printf("Host_Loadgame_f: loading light styles\n");
791 // load the light styles
797 for (i = 0;i < MAX_LIGHTSTYLES;i++)
801 COM_ParseToken_Simple(&t, false, false);
802 // if this is a 64 lightstyle savegame produced by Quake, stop now
803 // we have to check this because darkplaces may save more than 64
804 if (com_token[0] == '{')
809 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
812 if(developer_entityparsing.integer)
813 Con_Printf("Host_Loadgame_f: skipping until globals\n");
815 // now skip everything before the first opening brace
816 // (this is for forward compatibility, so that older versions (at
817 // least ones with this fix) can load savegames with extra data before the
818 // first brace, as might be produced by a later engine version)
822 if (!COM_ParseToken_Simple(&t, false, false))
824 if (com_token[0] == '{')
831 // load the edicts out of the savegame file
836 while (COM_ParseToken_Simple(&t, false, false))
837 if (!strcmp(com_token, "}"))
839 if (!COM_ParseToken_Simple(&start, false, false))
844 if (strcmp(com_token,"{"))
847 Host_Error ("First token isn't a brace");
852 if(developer_entityparsing.integer)
853 Con_Printf("Host_Loadgame_f: loading globals\n");
855 // parse the global vars
856 PRVM_ED_ParseGlobals (start);
861 if (entnum >= MAX_EDICTS)
864 Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
866 while (entnum >= prog->max_edicts)
867 PRVM_MEM_IncreaseEdicts();
868 ent = PRVM_EDICT_NUM(entnum);
869 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
870 ent->priv.server->free = false;
872 if(developer_entityparsing.integer)
873 Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
875 PRVM_ED_ParseEdict (start, ent);
877 // link it into the bsp tree
878 if (!ent->priv.server->free)
879 SV_LinkEdict (ent, false);
886 prog->num_edicts = entnum;
889 for (i = 0;i < NUM_SPAWN_PARMS;i++)
890 svs.clients[0].spawn_parms[i] = spawn_parms[i];
892 if(developer_entityparsing.integer)
893 Con_Printf("Host_Loadgame_f: skipping until extended data\n");
895 // read extended data if present
896 // the extended data is stored inside a /* */ comment block, which the
897 // parser intentionally skips, so we have to check for it manually here
900 while (*end == '\r' || *end == '\n')
902 if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
904 if(developer_entityparsing.integer)
905 Con_Printf("Host_Loadgame_f: loading extended data\n");
907 Con_Printf("Loading extended DarkPlaces savegame\n");
909 memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
910 memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
911 memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
912 while (COM_ParseToken_Simple(&t, false, false))
914 if (!strcmp(com_token, "sv.lightstyles"))
916 COM_ParseToken_Simple(&t, false, false);
918 COM_ParseToken_Simple(&t, false, false);
919 if (i >= 0 && i < MAX_LIGHTSTYLES)
920 strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
922 Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
924 else if (!strcmp(com_token, "sv.model_precache"))
926 COM_ParseToken_Simple(&t, false, false);
928 COM_ParseToken_Simple(&t, false, false);
929 if (i >= 0 && i < MAX_MODELS)
931 strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
932 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
935 Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
937 else if (!strcmp(com_token, "sv.sound_precache"))
939 COM_ParseToken_Simple(&t, false, false);
941 COM_ParseToken_Simple(&t, false, false);
942 if (i >= 0 && i < MAX_SOUNDS)
943 strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
945 Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
947 // skip any trailing text or unrecognized commands
948 while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
955 if(developer_entityparsing.integer)
956 Con_Printf("Host_Loadgame_f: finished\n");
960 // make sure we're connected to loopback
961 if (sv.active && cls.state == ca_disconnected)
962 CL_EstablishConnection("local:1");
965 //============================================================================
968 ======================
970 ======================
972 cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
973 void Host_Name_f (void)
976 qboolean valid_colors;
977 char newName[sizeof(host_client->name)];
979 if (Cmd_Argc () == 1)
981 Con_Printf("\"name\" is \"%s\"\n", cl_name.string);
985 if (Cmd_Argc () == 2)
986 strlcpy (newName, Cmd_Argv(1), sizeof (newName));
988 strlcpy (newName, Cmd_Args(), sizeof (newName));
990 if (cmd_source == src_command)
992 Cvar_Set ("_cl_name", newName);
996 if (realtime < host_client->nametime)
998 SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
1002 host_client->nametime = realtime + 5;
1004 // point the string back at updateclient->name to keep it safe
1005 strlcpy (host_client->name, newName, sizeof (host_client->name));
1007 for (i = 0, j = 0;host_client->name[i];i++)
1008 if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
1009 host_client->name[j++] = host_client->name[i];
1010 host_client->name[j] = 0;
1012 if(host_client->name[0] == 1 || host_client->name[0] == 2)
1013 // may interfere with chat area, and will needlessly beep; so let's add a ^7
1015 memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
1016 host_client->name[sizeof(host_client->name) - 1] = 0;
1017 host_client->name[0] = STRING_COLOR_TAG;
1018 host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
1021 COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
1022 if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
1025 l = strlen(host_client->name);
1026 if(l < sizeof(host_client->name) - 1)
1028 // duplicate the color tag to escape it
1029 host_client->name[i] = STRING_COLOR_TAG;
1030 host_client->name[i+1] = 0;
1031 //Con_DPrintf("abuse detected, adding another trailing color tag\n");
1035 // remove the last character to fix the color code
1036 host_client->name[l-1] = 0;
1037 //Con_DPrintf("abuse detected, removing a trailing color tag\n");
1041 // find the last color tag offset and decide if we need to add a reset tag
1042 for (i = 0, j = -1;host_client->name[i];i++)
1044 if (host_client->name[i] == STRING_COLOR_TAG)
1046 if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
1049 // if this happens to be a reset tag then we don't need one
1050 if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
1055 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]))
1061 if (host_client->name[i+1] == STRING_COLOR_TAG)
1068 // does not end in the default color string, so add it
1069 if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
1070 memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
1072 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1073 if (strcmp(host_client->old_name, host_client->name))
1075 if (host_client->spawned)
1076 SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
1077 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1078 // send notification to all clients
1079 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1080 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1081 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1082 SV_WriteNetnameIntoDemo(host_client);
1087 ======================
1089 ======================
1091 cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"};
1092 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
1093 void Host_Playermodel_f (void)
1096 char newPath[sizeof(host_client->playermodel)];
1098 if (Cmd_Argc () == 1)
1100 Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
1104 if (Cmd_Argc () == 2)
1105 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1107 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1109 for (i = 0, j = 0;newPath[i];i++)
1110 if (newPath[i] != '\r' && newPath[i] != '\n')
1111 newPath[j++] = newPath[i];
1114 if (cmd_source == src_command)
1116 Cvar_Set ("_cl_playermodel", newPath);
1121 if (realtime < host_client->nametime)
1123 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1127 host_client->nametime = realtime + 5;
1130 // point the string back at updateclient->name to keep it safe
1131 strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
1132 if( prog->fieldoffsets.playermodel >= 0 )
1133 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1134 if (strcmp(host_client->old_model, host_client->playermodel))
1136 strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
1137 /*// send notification to all clients
1138 MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
1139 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1140 MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
1145 ======================
1147 ======================
1149 cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"};
1150 void Host_Playerskin_f (void)
1153 char newPath[sizeof(host_client->playerskin)];
1155 if (Cmd_Argc () == 1)
1157 Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
1161 if (Cmd_Argc () == 2)
1162 strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
1164 strlcpy (newPath, Cmd_Args(), sizeof (newPath));
1166 for (i = 0, j = 0;newPath[i];i++)
1167 if (newPath[i] != '\r' && newPath[i] != '\n')
1168 newPath[j++] = newPath[i];
1171 if (cmd_source == src_command)
1173 Cvar_Set ("_cl_playerskin", newPath);
1178 if (realtime < host_client->nametime)
1180 SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
1184 host_client->nametime = realtime + 5;
1187 // point the string back at updateclient->name to keep it safe
1188 strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
1189 if( prog->fieldoffsets.playerskin >= 0 )
1190 PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1191 if (strcmp(host_client->old_skin, host_client->playerskin))
1193 //if (host_client->spawned)
1194 // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
1195 strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
1196 /*// send notification to all clients
1197 MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
1198 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1199 MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
1203 void Host_Version_f (void)
1205 Con_Printf("Version: %s build %s\n", gamename, buildstring);
1208 void Host_Say(qboolean teamonly)
1214 // LordHavoc: long say messages
1216 qboolean fromServer = false;
1218 if (cmd_source == src_command)
1220 if (cls.state == ca_dedicated)
1227 Cmd_ForwardToServer ();
1232 if (Cmd_Argc () < 2)
1235 if (!teamplay.integer)
1245 // note this uses the chat prefix \001
1246 if (!fromServer && !teamonly)
1247 dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1);
1248 else if (!fromServer && teamonly)
1249 dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1);
1250 else if(*(sv_adminnick.string))
1251 dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1);
1253 dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1);
1254 p2 = text + strlen(text);
1255 while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted)))
1257 if (p2[-1] == '\"' && quoted)
1262 strlcat(text, "\n", sizeof(text));
1264 // note: save is not a valid edict if fromServer is true
1266 for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
1267 if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
1268 SV_ClientPrint(text);
1271 if (cls.state == ca_dedicated)
1272 Con_Print(&text[1]);
1276 void Host_Say_f(void)
1282 void Host_Say_Team_f(void)
1288 void Host_Tell_f(void)
1290 const char *playername_start = NULL;
1291 size_t playername_length = 0;
1292 int playernumber = 0;
1295 const char *p1, *p2;
1296 char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
1297 qboolean fromServer = false;
1299 if (cmd_source == src_command)
1301 if (cls.state == ca_dedicated)
1305 Cmd_ForwardToServer ();
1310 if (Cmd_Argc () < 2)
1313 // note this uses the chat prefix \001
1315 dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
1316 else if(*(sv_adminnick.string))
1317 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
1319 dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
1322 p2 = p1 + strlen(p1);
1323 // remove the target name
1324 while (p1 < p2 && *p1 == ' ')
1329 while (p1 < p2 && *p1 == ' ')
1331 while (p1 < p2 && isdigit(*p1))
1333 playernumber = playernumber * 10 + (*p1 - '0');
1341 playername_start = p1;
1342 while (p1 < p2 && *p1 != '"')
1344 playername_length = p1 - playername_start;
1350 playername_start = p1;
1351 while (p1 < p2 && *p1 != ' ')
1353 playername_length = p1 - playername_start;
1355 while (p1 < p2 && *p1 == ' ')
1357 if(playername_start)
1359 // set playernumber to the right client
1361 if(playername_length >= sizeof(namebuf))
1364 Con_Print("Host_Tell: too long player name/ID\n");
1366 SV_ClientPrint("Host_Tell: too long player name/ID\n");
1369 memcpy(namebuf, playername_start, playername_length);
1370 namebuf[playername_length] = 0;
1371 for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
1373 if (!svs.clients[playernumber].active)
1375 if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
1379 if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
1382 Con_Print("Host_Tell: invalid player name/ID\n");
1384 SV_ClientPrint("Host_Tell: invalid player name/ID\n");
1387 // remove trailing newlines
1388 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1390 // remove quotes if present
1396 else if (fromServer)
1397 Con_Print("Host_Tell: missing end quote\n");
1399 SV_ClientPrint("Host_Tell: missing end quote\n");
1401 while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
1404 return; // empty say
1405 for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
1411 host_client = svs.clients + playernumber;
1412 SV_ClientPrint(text);
1422 cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
1423 void Host_Color(int changetop, int changebottom)
1425 int top, bottom, playercolor;
1427 // get top and bottom either from the provided values or the current values
1428 // (allows changing only top or bottom, or both at once)
1429 top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
1430 bottom = changebottom >= 0 ? changebottom : cl_color.integer;
1434 // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
1440 playercolor = top*16 + bottom;
1442 if (cmd_source == src_command)
1444 Cvar_SetValueQuick(&cl_color, playercolor);
1448 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1451 if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
1453 Con_DPrint("Calling SV_ChangeTeam\n");
1454 prog->globals.server->time = sv.time;
1455 prog->globals.generic[OFS_PARM0] = playercolor;
1456 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1457 PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
1462 if (host_client->edict)
1464 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1465 val->_float = playercolor;
1466 host_client->edict->fields.server->team = bottom + 1;
1468 host_client->colors = playercolor;
1469 if (host_client->old_colors != host_client->colors)
1471 host_client->old_colors = host_client->colors;
1472 // send notification to all clients
1473 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1474 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1475 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1480 void Host_Color_f(void)
1484 if (Cmd_Argc() == 1)
1486 Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
1487 Con_Print("color <0-15> [0-15]\n");
1491 if (Cmd_Argc() == 2)
1492 top = bottom = atoi(Cmd_Argv(1));
1495 top = atoi(Cmd_Argv(1));
1496 bottom = atoi(Cmd_Argv(2));
1498 Host_Color(top, bottom);
1501 void Host_TopColor_f(void)
1503 if (Cmd_Argc() == 1)
1505 Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
1506 Con_Print("topcolor <0-15>\n");
1510 Host_Color(atoi(Cmd_Argv(1)), -1);
1513 void Host_BottomColor_f(void)
1515 if (Cmd_Argc() == 1)
1517 Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
1518 Con_Print("bottomcolor <0-15>\n");
1522 Host_Color(-1, atoi(Cmd_Argv(1)));
1525 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
1526 void Host_Rate_f(void)
1530 if (Cmd_Argc() != 2)
1532 Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
1533 Con_Print("rate <bytespersecond>\n");
1537 rate = atoi(Cmd_Argv(1));
1539 if (cmd_source == src_command)
1541 Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
1545 host_client->rate = rate;
1553 void Host_Kill_f (void)
1555 if (host_client->edict->fields.server->health <= 0)
1557 SV_ClientPrint("Can't suicide -- already dead!\n");
1561 prog->globals.server->time = sv.time;
1562 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1563 PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
1572 void Host_Pause_f (void)
1574 if (!pausable.integer)
1575 SV_ClientPrint("Pause not allowed.\n");
1579 SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
1580 // send notification to all clients
1581 MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
1582 MSG_WriteByte(&sv.reliable_datagram, sv.paused);
1587 ======================
1589 LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
1590 LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
1591 ======================
1593 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)"};
1594 static void Host_PModel_f (void)
1599 if (Cmd_Argc () == 1)
1601 Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
1604 i = atoi(Cmd_Argv(1));
1606 if (cmd_source == src_command)
1608 if (cl_pmodel.integer == i)
1610 Cvar_SetValue ("_cl_pmodel", i);
1611 if (cls.state == ca_connected)
1612 Cmd_ForwardToServer ();
1616 if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
1620 //===========================================================================
1628 void Host_PreSpawn_f (void)
1630 if (host_client->spawned)
1632 Con_Print("prespawn not valid -- already spawned\n");
1636 if (host_client->netconnection)
1638 SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize);
1639 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1640 MSG_WriteByte (&host_client->netconnection->message, 2);
1641 host_client->sendsignon = 0; // enable unlimited sends again
1644 // reset the name change timer because the client will send name soon
1645 host_client->nametime = 0;
1653 void Host_Spawn_f (void)
1657 int stats[MAX_CL_STATS];
1659 if (host_client->spawned)
1661 Con_Print("Spawn not valid -- already spawned\n");
1665 // reset name change timer again because they might want to change name
1666 // again in the first 5 seconds after connecting
1667 host_client->nametime = 0;
1669 // LordHavoc: moved this above the QC calls at FrikaC's request
1670 // LordHavoc: commented this out
1671 //if (host_client->netconnection)
1672 // SZ_Clear (&host_client->netconnection->message);
1674 // run the entrance script
1677 // loaded games are fully initialized already
1678 if (prog->funcoffsets.RestoreGame)
1680 Con_DPrint("Calling RestoreGame\n");
1681 prog->globals.server->time = sv.time;
1682 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1683 PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
1688 //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);
1690 // copy spawn parms out of the client_t
1691 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1692 (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
1694 // call the spawn function
1695 host_client->clientconnectcalled = true;
1696 prog->globals.server->time = sv.time;
1697 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1698 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1700 if (cls.state == ca_dedicated)
1701 Con_Printf("%s connected\n", host_client->name);
1703 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1706 if (!host_client->netconnection)
1709 // send time of update
1710 MSG_WriteByte (&host_client->netconnection->message, svc_time);
1711 MSG_WriteFloat (&host_client->netconnection->message, sv.time);
1713 // send all current names, colors, and frag counts
1714 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1716 if (!client->active)
1718 MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
1719 MSG_WriteByte (&host_client->netconnection->message, i);
1720 MSG_WriteString (&host_client->netconnection->message, client->name);
1721 MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
1722 MSG_WriteByte (&host_client->netconnection->message, i);
1723 MSG_WriteShort (&host_client->netconnection->message, client->frags);
1724 MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
1725 MSG_WriteByte (&host_client->netconnection->message, i);
1726 MSG_WriteByte (&host_client->netconnection->message, client->colors);
1729 // send all current light styles
1730 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1732 if (sv.lightstyles[i][0])
1734 MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
1735 MSG_WriteByte (&host_client->netconnection->message, (char)i);
1736 MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
1741 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1742 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
1743 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
1745 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1746 MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
1747 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
1749 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1750 MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
1751 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
1753 MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
1754 MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
1755 MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
1758 // Never send a roll angle, because savegames can catch the server
1759 // in a state where it is expecting the client to correct the angle
1760 // and it won't happen if the game was just loaded, so you wind up
1761 // with a permanent head tilt
1764 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1765 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
1766 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
1767 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1771 MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
1772 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
1773 MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
1774 MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
1777 SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
1779 MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
1780 MSG_WriteByte (&host_client->netconnection->message, 3);
1788 void Host_Begin_f (void)
1790 host_client->spawned = true;
1792 // LordHavoc: note: this code also exists in SV_DropClient
1796 for (i = 0;i < svs.maxclients;i++)
1797 if (svs.clients[i].active && !svs.clients[i].spawned)
1799 if (i == svs.maxclients)
1801 Con_Printf("Loaded game, everyone rejoined - unpausing\n");
1802 sv.paused = sv.loadgame = false; // we're basically done with loading now
1807 //===========================================================================
1814 Kicks a user off of the server
1817 void Host_Kick_f (void)
1820 const char *message = NULL;
1823 qboolean byNumber = false;
1831 if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
1833 i = (int)(atof(Cmd_Argv(2)) - 1);
1834 if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
1840 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1842 if (!host_client->active)
1844 if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1849 if (i < svs.maxclients)
1851 if (cmd_source == src_command)
1853 if (cls.state == ca_dedicated)
1856 who = cl_name.string;
1861 // can't kick yourself!
1862 if (host_client == save)
1867 message = Cmd_Args();
1868 COM_ParseToken_Simple(&message, false, false);
1871 message++; // skip the #
1872 while (*message == ' ') // skip white space
1874 message += strlen(Cmd_Argv(2)); // skip the number
1876 while (*message && *message == ' ')
1880 SV_ClientPrintf("Kicked by %s: %s\n", who, message);
1882 SV_ClientPrintf("Kicked by %s\n", who);
1883 SV_DropClient (false); // kicked
1891 ===============================================================================
1895 ===============================================================================
1903 void Host_Give_f (void)
1911 SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
1916 v = atoi (Cmd_Argv(2));
1930 // MED 01/04/97 added hipnotic give stuff
1931 if (gamemode == GAME_HIPNOTIC)
1936 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
1938 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
1940 else if (t[0] == '9')
1941 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
1942 else if (t[0] == '0')
1943 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
1944 else if (t[0] >= '2')
1945 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1950 host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
1955 if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
1958 host_client->edict->fields.server->ammo_shells = v;
1961 if (gamemode == GAME_ROGUE)
1963 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
1966 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1967 host_client->edict->fields.server->ammo_nails = v;
1972 host_client->edict->fields.server->ammo_nails = v;
1976 if (gamemode == GAME_ROGUE)
1978 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
1982 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
1983 host_client->edict->fields.server->ammo_nails = v;
1988 if (gamemode == GAME_ROGUE)
1990 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
1994 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
1995 host_client->edict->fields.server->ammo_rockets = v;
2000 host_client->edict->fields.server->ammo_rockets = v;
2004 if (gamemode == GAME_ROGUE)
2006 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
2010 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2011 host_client->edict->fields.server->ammo_rockets = v;
2016 host_client->edict->fields.server->health = v;
2019 if (gamemode == GAME_ROGUE)
2021 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
2025 if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
2026 host_client->edict->fields.server->ammo_cells = v;
2031 host_client->edict->fields.server->ammo_cells = v;
2035 if (gamemode == GAME_ROGUE)
2037 val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
2041 if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
2042 host_client->edict->fields.server->ammo_cells = v;
2049 prvm_edict_t *FindViewthing (void)
2054 for (i=0 ; i<prog->num_edicts ; i++)
2056 e = PRVM_EDICT_NUM(i);
2057 if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
2060 Con_Print("No viewthing on map\n");
2069 void Host_Viewmodel_f (void)
2078 e = FindViewthing ();
2083 m = Mod_ForName (Cmd_Argv(1), false, true, false);
2084 if (!m || !m->loaded || !m->Draw)
2086 Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
2090 e->fields.server->frame = 0;
2091 cl.model_precache[(int)e->fields.server->modelindex] = m;
2099 void Host_Viewframe_f (void)
2109 e = FindViewthing ();
2113 m = cl.model_precache[(int)e->fields.server->modelindex];
2115 f = atoi(Cmd_Argv(1));
2116 if (f >= m->numframes)
2119 e->fields.server->frame = f;
2123 void PrintFrameName (dp_model_t *m, int frame)
2126 Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
2128 Con_Printf("frame %i\n", frame);
2136 void Host_Viewnext_f (void)
2145 e = FindViewthing ();
2149 m = cl.model_precache[(int)e->fields.server->modelindex];
2151 e->fields.server->frame = e->fields.server->frame + 1;
2152 if (e->fields.server->frame >= m->numframes)
2153 e->fields.server->frame = m->numframes - 1;
2155 PrintFrameName (m, (int)e->fields.server->frame);
2163 void Host_Viewprev_f (void)
2172 e = FindViewthing ();
2177 m = cl.model_precache[(int)e->fields.server->modelindex];
2179 e->fields.server->frame = e->fields.server->frame - 1;
2180 if (e->fields.server->frame < 0)
2181 e->fields.server->frame = 0;
2183 PrintFrameName (m, (int)e->fields.server->frame);
2187 ===============================================================================
2191 ===============================================================================
2200 void Host_Startdemos_f (void)
2204 if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
2210 Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
2213 Con_DPrintf("%i demo(s) in loop\n", c);
2215 for (i=1 ; i<c+1 ; i++)
2216 strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
2218 // LordHavoc: clear the remaining slots
2219 for (;i <= MAX_DEMOS;i++)
2220 cls.demos[i-1][0] = 0;
2222 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
2236 Return to looping demos
2239 void Host_Demos_f (void)
2241 if (cls.state == ca_dedicated)
2243 if (cls.demonum == -1)
2253 Return to looping demos
2256 void Host_Stopdemo_f (void)
2258 if (!cls.demoplayback)
2261 Host_ShutdownServer ();
2264 void Host_SendCvar_f (void)
2268 const char *cvarname;
2273 cvarname = Cmd_Argv(1);
2274 if (cls.state == ca_connected)
2276 c = Cvar_FindVar(cvarname);
2277 // LordHavoc: if there is no such cvar or if it is private, send a
2278 // reply indicating that it has no value
2279 if(!c || (c->flags & CVAR_PRIVATE))
2280 Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
2282 Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
2285 if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
2289 if (cls.state != ca_dedicated)
2293 for(;i<svs.maxclients;i++)
2294 if(svs.clients[i].active && svs.clients[i].netconnection)
2296 host_client = &svs.clients[i];
2297 Host_ClientCommands("sendcvar %s\n", cvarname);
2302 static void MaxPlayers_f(void)
2306 if (Cmd_Argc() != 2)
2308 Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
2314 Con_Print("maxplayers can not be changed while a server is running.\n");
2318 n = atoi(Cmd_Argv(1));
2319 n = bound(1, n, MAX_SCOREBOARD);
2320 Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
2323 Mem_Free(svs.clients);
2325 svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
2327 Cvar_Set ("deathmatch", "0");
2329 Cvar_Set ("deathmatch", "1");
2332 //=============================================================================
2334 // QuakeWorld commands
2337 =====================
2340 Send the rest of the command line over as
2341 an unconnected command.
2342 =====================
2344 void Host_Rcon_f (void) // credit: taken from QuakeWorld
2348 lhnetsocket_t *mysocket;
2350 if (!rcon_password.string || !rcon_password.string[0])
2352 Con_Printf ("You must set rcon_password before issuing an rcon command.\n");
2356 for (i = 0;rcon_password.string[i];i++)
2358 if (ISWHITESPACE(rcon_password.string[i]))
2360 Con_Printf("rcon_password is not allowed to have any whitespace.\n");
2366 to = cls.netcon->peeraddress;
2369 if (!rcon_address.string[0])
2371 Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
2374 LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
2376 mysocket = NetConn_ChooseClientSocketForAddress(&to);
2379 // simply put together the rcon packet and send it
2380 NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to);
2385 ====================
2388 user <name or userid>
2390 Dump userdata / masterdata for a user
2391 ====================
2393 void Host_User_f (void) // credit: taken from QuakeWorld
2398 if (Cmd_Argc() != 2)
2400 Con_Printf ("Usage: user <username / userid>\n");
2404 uid = atoi(Cmd_Argv(1));
2406 for (i = 0;i < cl.maxclients;i++)
2408 if (!cl.scores[i].name[0])
2410 if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
2412 InfoString_Print(cl.scores[i].qw_userinfo);
2416 Con_Printf ("User not in server.\n");
2420 ====================
2423 Dump userids for all current players
2424 ====================
2426 void Host_Users_f (void) // credit: taken from QuakeWorld
2432 Con_Printf ("userid frags name\n");
2433 Con_Printf ("------ ----- ----\n");
2434 for (i = 0;i < cl.maxclients;i++)
2436 if (cl.scores[i].name[0])
2438 Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name);
2443 Con_Printf ("%i total users\n", c);
2448 Host_FullServerinfo_f
2450 Sent by server when serverinfo changes
2453 // TODO: shouldn't this be a cvar instead?
2454 void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
2457 if (Cmd_Argc() != 2)
2459 Con_Printf ("usage: fullserverinfo <complete info string>\n");
2463 strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
2464 InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
2465 cl.qw_teamplay = atoi(temp);
2472 Allow clients to change userinfo
2476 void Host_FullInfo_f (void) // credit: taken from QuakeWorld
2483 if (Cmd_Argc() != 2)
2485 Con_Printf ("fullinfo <complete info string>\n");
2495 while (*s && *s != '\\')
2501 Con_Printf ("MISSING VALUE\n");
2507 while (*s && *s != '\\')
2514 CL_SetInfo(key, value, false, false, false, false);
2522 Allow clients to change userinfo
2525 void Host_SetInfo_f (void) // credit: taken from QuakeWorld
2527 if (Cmd_Argc() == 1)
2529 InfoString_Print(cls.userinfo);
2532 if (Cmd_Argc() != 3)
2534 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
2537 CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
2541 ====================
2544 packet <destination> <contents>
2546 Contents allows \n escape character
2547 ====================
2549 void Host_Packet_f (void) // credit: taken from QuakeWorld
2555 lhnetaddress_t address;
2556 lhnetsocket_t *mysocket;
2558 if (Cmd_Argc() != 3)
2560 Con_Printf ("packet <destination> <contents>\n");
2564 if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
2566 Con_Printf ("Bad address\n");
2572 send[0] = send[1] = send[2] = send[3] = 0xff;
2574 l = (int)strlen (in);
2575 for (i=0 ; i<l ; i++)
2577 if (out >= send + sizeof(send) - 1)
2579 if (in[i] == '\\' && in[i+1] == 'n')
2584 else if (in[i] == '\\' && in[i+1] == '0')
2589 else if (in[i] == '\\' && in[i+1] == 't')
2594 else if (in[i] == '\\' && in[i+1] == 'r')
2599 else if (in[i] == '\\' && in[i+1] == '"')
2608 mysocket = NetConn_ChooseClientSocketForAddress(&address);
2610 mysocket = NetConn_ChooseServerSocketForAddress(&address);
2612 NetConn_Write(mysocket, send, out - send, &address);
2616 ====================
2619 Send back ping and packet loss update for all current players to this player
2620 ====================
2622 void Host_Pings_f (void)
2624 int i, j, ping, packetloss;
2627 if (!host_client->netconnection)
2630 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2632 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
2633 MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport");
2635 for (i = 0;i < svs.maxclients;i++)
2638 if (svs.clients[i].netconnection)
2639 for (j = 0;j < NETGRAPH_PACKETS;j++)
2640 if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET)
2642 packetloss = packetloss * 100 / NETGRAPH_PACKETS;
2643 ping = (int)floor(svs.clients[i].ping*1000+0.5);
2644 ping = bound(0, ping, 9999);
2645 if (sv.protocol == PROTOCOL_QUAKEWORLD)
2647 // send qw_svc_updateping and qw_svc_updatepl messages
2648 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping);
2649 MSG_WriteShort(&host_client->netconnection->message, ping);
2650 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl);
2651 MSG_WriteByte(&host_client->netconnection->message, packetloss);
2655 // write the string into the packet as multiple unterminated strings to avoid needing a local buffer
2656 dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss);
2657 MSG_WriteUnterminatedString(&host_client->netconnection->message, temp);
2660 if (sv.protocol != PROTOCOL_QUAKEWORLD)
2661 MSG_WriteString(&host_client->netconnection->message, "\n");
2664 void Host_PingPLReport_f(void)
2668 if (l > cl.maxclients)
2670 for (i = 0;i < l;i++)
2672 cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
2673 cl.scores[i].qw_packetloss = atoi(Cmd_Argv(1+i*2+1));
2677 //=============================================================================
2684 void Host_InitCommands (void)
2686 dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
2688 Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
2689 Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
2690 if (gamemode == GAME_NEHAHRA)
2692 Cmd_AddCommand_WithClientCommand ("max", NULL, Host_God_f, "god mode (invulnerability)");
2693 Cmd_AddCommand_WithClientCommand ("monster", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2694 Cmd_AddCommand_WithClientCommand ("scrag", NULL, Host_Fly_f, "fly mode (flight)");
2695 Cmd_AddCommand_WithClientCommand ("wraith", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2696 Cmd_AddCommand_WithClientCommand ("gimme", NULL, Host_Give_f, "alter inventory");
2700 Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
2701 Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
2702 Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
2703 Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
2704 Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
2706 Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
2707 Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
2708 Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
2709 Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
2710 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)");
2711 Cmd_AddCommand ("version", Host_Version_f, "print engine version");
2712 Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
2713 Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
2714 Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
2715 Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
2716 Cmd_AddCommand_WithClientCommand ("pause", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
2717 Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
2718 Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
2719 Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
2720 Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
2722 Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
2723 Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
2724 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
2726 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
2727 Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
2728 Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
2729 Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
2731 Cvar_RegisterVariable (&cl_name);
2732 Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
2733 Cvar_RegisterVariable (&cl_color);
2734 Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
2735 Cvar_RegisterVariable (&cl_rate);
2736 Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
2737 if (gamemode == GAME_NEHAHRA)
2739 Cvar_RegisterVariable (&cl_pmodel);
2740 Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "change your player model choice (Nehahra specific)");
2743 // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
2744 Cvar_RegisterVariable (&cl_playermodel);
2745 Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
2746 Cvar_RegisterVariable (&cl_playerskin);
2747 Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
2749 Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
2750 Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
2751 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)");
2752 Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
2754 Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
2756 Cvar_RegisterVariable (&rcon_password);
2757 Cvar_RegisterVariable (&rcon_address);
2758 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)");
2759 Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
2760 Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
2761 Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
2762 Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
2763 Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
2764 Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
2765 Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
2766 Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
2768 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)");
2769 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)");
2771 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)");
2772 Cvar_RegisterVariable (&r_fixtrans_auto);
2774 Cvar_RegisterVariable (&team);
2775 Cvar_RegisterVariable (&skin);
2776 Cvar_RegisterVariable (&noaim);
2778 Cvar_RegisterVariable(&sv_cheats);
2779 Cvar_RegisterVariable(&sv_adminnick);
2780 Cvar_RegisterVariable(&sv_status_privacy);
2781 Cvar_RegisterVariable(&sv_status_show_qcstatus);
2784 void Host_NoOperation_f(void)