]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - host_cmd.c
Delete the cmd_clientfromserver interpreter. Use cmd_client instead
[xonotic/darkplaces.git] / host_cmd.c
index f2d6af53dc5b54caa621c608c9c0960337fc01f0..46b261cc43c4131287e6c9a8fe2c38de10d652a8 100644 (file)
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "sv_demo.h"
 #include "image.h"
 
+#include "prvm_cmds.h"
 #include "utf8lib.h"
 
 // for secure rcon authentication
@@ -30,20 +31,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <time.h>
 
 int current_skill;
-cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
-cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
-cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
-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."};
-cvar_t sv_namechangetimer = {CVAR_SAVE, "sv_namechangetimer", "5", "how often to allow name changes, in seconds (prevents people from using animated names and other tricks"};
-cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"};
-cvar_t rcon_secure = {CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
-cvar_t rcon_secure_challengetimeout = {0, "rcon_secure_challengetimeout", "5", "challenge-based secure rcon: time out requests if no challenge came within this time interval"};
-cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
-cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
-cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
-cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
-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)"};
-qboolean allowcheats = false;
+cvar_t sv_cheats = {CVAR_SERVER | CVAR_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
+cvar_t sv_adminnick = {CVAR_SERVER | CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"};
+cvar_t sv_status_privacy = {CVAR_SERVER | CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"};
+cvar_t sv_status_show_qcstatus = {CVAR_SERVER | 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."};
+cvar_t sv_namechangetimer = {CVAR_SERVER | CVAR_SAVE, "sv_namechangetimer", "5", "how often to allow name changes, in seconds (prevents people from using animated names and other tricks"};
+cvar_t rcon_password = {CVAR_CLIENT | CVAR_SERVER | CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"};
+cvar_t rcon_secure = {CVAR_CLIENT | CVAR_SERVER | CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
+cvar_t rcon_secure_challengetimeout = {CVAR_CLIENT, "rcon_secure_challengetimeout", "5", "challenge-based secure rcon: time out requests if no challenge came within this time interval"};
+cvar_t rcon_address = {CVAR_CLIENT, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
+cvar_t team = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
+cvar_t skin = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
+cvar_t noaim = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
+cvar_t r_fixtrans_auto = {CVAR_CLIENT, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"};
 
 extern qboolean host_shuttingdown;
 extern cvar_t developer_entityparsing;
@@ -54,7 +54,7 @@ Host_Quit_f
 ==================
 */
 
-void Host_Quit_f (void)
+void Host_Quit_f(cmd_state_t *cmd)
 {
        if(host_shuttingdown)
                Con_Printf("shutting down already!\n");
@@ -67,7 +67,7 @@ void Host_Quit_f (void)
 Host_Status_f
 ==================
 */
-static void Host_Status_f (void)
+static void Host_Status_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        char qcstatus[256];
@@ -78,12 +78,12 @@ static void Host_Status_f (void)
        int frags;
        char vabuf[1024];
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                // if running a client, try to send over network so the client's status report parser will see the report
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -95,19 +95,19 @@ static void Host_Status_f (void)
                return;
 
        in = 0;
-       if (Cmd_Argc() == 2)
+       if (Cmd_Argc(cmd) == 2)
        {
-               if (strcmp(Cmd_Argv(1), "1") == 0)
+               if (strcmp(Cmd_Argv(cmd, 1), "1") == 0)
                        in = 1;
-               else if (strcmp(Cmd_Argv(1), "2") == 0)
+               else if (strcmp(Cmd_Argv(cmd, 1), "2") == 0)
                        in = 2;
        }
 
        for (players = 0, i = 0;i < svs.maxclients;i++)
                if (svs.clients[i].active)
                        players++;
-       print ("host:     %s\n", Cvar_VariableString ("hostname"));
-       print ("version:  %s build %s\n", gamename, buildstring);
+       print ("host:     %s\n", Cvar_VariableString (&cvars_all, "hostname", CVAR_SERVER));
+       print ("version:  %s build %s (gamename %s)\n", gamename, buildstring, gamenetworkfiltername);
        print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol));
        print ("map:      %s\n", sv.name);
        print ("timing:   %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
@@ -148,10 +148,10 @@ static void Host_Status_f (void)
                        ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
                }
 
-               if(sv_status_privacy.integer && cmd_source != src_command)
+               if(sv_status_privacy.integer && cmd->source != src_command)
                        strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48);
                else
-                       strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 48);
+                       strlcpy(ip, (client->netconnection && *client->netconnection->address) ? client->netconnection->address : "botclient", 48);
 
                frags = client->frags;
 
@@ -177,13 +177,13 @@ static void Host_Status_f (void)
                {
                        if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99)
                        {
-                               // LordHavoc: this is very touchy because we must maintain ProQuake compatible status output
+                               // LadyHavoc: this is very touchy because we must maintain ProQuake compatible status output
                                print ("#%-2u %-16.16s  %3i  %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
                                print ("   %s\n", ip);
                        }
                        else
                        {
-                               // LordHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
+                               // LadyHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway...
                                print ("#%-3u %-16.16s %4i  %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
                                print ("   %s\n", ip);
                        }
@@ -207,12 +207,12 @@ Host_God_f
 Sets client to godmode
 ==================
 */
-static void Host_God_f (void)
+static void Host_God_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
-       if (!allowcheats)
+       if (!sv_cheats.integer)
        {
-               SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
+               SV_ClientPrint("No cheats allowed. Set sv_cheats to 1 in the server console to enable.\n");
                return;
        }
 
@@ -223,12 +223,12 @@ static void Host_God_f (void)
                SV_ClientPrint("godmode ON\n");
 }
 
-static void Host_Notarget_f (void)
+static void Host_Notarget_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
-       if (!allowcheats)
+       if (!sv_cheats.integer)
        {
-               SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
+               SV_ClientPrint("No cheats allowed. Set sv_cheats to 1 in the server console to enable.\n");
                return;
        }
 
@@ -241,12 +241,12 @@ static void Host_Notarget_f (void)
 
 qboolean noclip_anglehack;
 
-static void Host_Noclip_f (void)
+static void Host_Noclip_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
-       if (!allowcheats)
+       if (!sv_cheats.integer)
        {
-               SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
+               SV_ClientPrint("No cheats allowed. Set sv_cheats to 1 in the server console to enable.\n");
                return;
        }
 
@@ -271,12 +271,12 @@ Host_Fly_f
 Sets client to flymode
 ==================
 */
-static void Host_Fly_f (void)
+static void Host_Fly_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
-       if (!allowcheats)
+       if (!sv_cheats.integer)
        {
-               SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
+               SV_ClientPrint("No cheats allowed. Set sv_cheats to 1 in the server console to enable.\n");
                return;
        }
 
@@ -299,19 +299,18 @@ Host_Ping_f
 
 ==================
 */
-void Host_Pings_f (void); // called by Host_Ping_f
-static void Host_Ping_f (void)
+static void Host_Ping_f(cmd_state_t *cmd)
 {
        int i;
        client_t *client;
        void (*print) (const char *fmt, ...);
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                // if running a client, try to send over network so the client's ping report parser will see the report
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -329,10 +328,31 @@ static void Host_Ping_f (void)
                        continue;
                print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
        }
+}
 
-       // 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)
-       // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
-       //Host_Pings_f();
+// Disable cheats if sv_cheats is turned off
+static void Host_DisableCheats_c(char *value)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       int i = 0;
+
+       if (value[0] == '0' && !value[1])
+       {
+               while (svs.clients[i].edict)
+               {
+                       if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_GODMODE))
+                               PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_GODMODE;
+                       if (((int)PRVM_serveredictfloat(svs.clients[i].edict, flags) & FL_NOTARGET))
+                               PRVM_serveredictfloat(svs.clients[i].edict, flags) = (int)PRVM_serveredictfloat(svs.clients[i].edict, flags) ^ FL_NOTARGET;
+                       if (PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_NOCLIP ||
+                               PRVM_serveredictfloat(svs.clients[i].edict, movetype) == MOVETYPE_FLY)
+                       {
+                               noclip_anglehack = false;
+                               PRVM_serveredictfloat(svs.clients[i].edict, movetype) = MOVETYPE_WALK;
+                       }
+                       i++;
+               }
+       }
 }
 
 /*
@@ -352,11 +372,11 @@ map <servername>
 command from the console.  Active clients are kicked off.
 ======================
 */
-static void Host_Map_f (void)
+static void Host_Map_f(cmd_state_t *cmd)
 {
        char level[MAX_QPATH];
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Print("map <levelname> : start a new game (kicks off all players)\n");
                return;
@@ -364,7 +384,7 @@ static void Host_Map_f (void)
 
        // GAME_DELUXEQUAKE - clear warpmark (used by QC)
        if (gamemode == GAME_DELUXEQUAKE)
-               Cvar_Set("warpmark", "");
+               Cvar_Set(&cvars_all, "warpmark", "");
 
        cls.demonum = -1;               // stop demo loop in case this fails
 
@@ -379,14 +399,15 @@ static void Host_Map_f (void)
                svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
        }
 
+#ifdef CONFIG_MENU
        // remove menu
        if (key_dest == key_menu || key_dest == key_menu_grabbed)
                MR_ToggleMenu(0);
+#endif
        key_dest = key_game;
 
        svs.serverflags = 0;                    // haven't completed an episode yet
-       allowcheats = sv_cheats.integer != 0;
-       strlcpy(level, Cmd_Argv(1), sizeof(level));
+       strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
        SV_SpawnServer(level);
        if (sv.active && cls.state == ca_disconnected)
                CL_EstablishConnection("local:1", -2);
@@ -399,29 +420,30 @@ Host_Changelevel_f
 Goes to a new map, taking all clients along
 ==================
 */
-static void Host_Changelevel_f (void)
+static void Host_Changelevel_f(cmd_state_t *cmd)
 {
        char level[MAX_QPATH];
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Print("changelevel <levelname> : continue game on a new level\n");
                return;
        }
        // HACKHACKHACK
        if (!sv.active) {
-               Host_Map_f();
+               Host_Map_f(cmd);
                return;
        }
 
+#ifdef CONFIG_MENU
        // remove menu
        if (key_dest == key_menu || key_dest == key_menu_grabbed)
                MR_ToggleMenu(0);
+#endif
        key_dest = key_game;
 
        SV_SaveSpawnparms ();
-       allowcheats = sv_cheats.integer != 0;
-       strlcpy(level, Cmd_Argv(1), sizeof(level));
+       strlcpy(level, Cmd_Argv(cmd, 1), sizeof(level));
        SV_SpawnServer(level);
        if (sv.active && cls.state == ca_disconnected)
                CL_EstablishConnection("local:1", -2);
@@ -434,11 +456,11 @@ Host_Restart_f
 Restarts the current server for a dead player
 ==================
 */
-static void Host_Restart_f (void)
+static void Host_Restart_f(cmd_state_t *cmd)
 {
        char mapname[MAX_QPATH];
 
-       if (Cmd_Argc() != 1)
+       if (Cmd_Argc(cmd) != 1)
        {
                Con_Print("restart : restart current level\n");
                return;
@@ -449,12 +471,13 @@ static void Host_Restart_f (void)
                return;
        }
 
+#ifdef CONFIG_MENU
        // remove menu
        if (key_dest == key_menu || key_dest == key_menu_grabbed)
                MR_ToggleMenu(0);
+#endif
        key_dest = key_game;
 
-       allowcheats = sv_cheats.integer != 0;
        strlcpy(mapname, sv.name, sizeof(mapname));
        SV_SpawnServer(mapname);
        if (sv.active && cls.state == ca_disconnected)
@@ -469,7 +492,7 @@ This command causes the client to wait for the signon messages again.
 This is sent just before a server changes levels
 ==================
 */
-void Host_Reconnect_f (void)
+void Host_Reconnect_f(cmd_state_t *cmd)
 {
        char temp[128];
        // if not connected, reconnect to the most recent server
@@ -493,9 +516,9 @@ void Host_Reconnect_f (void)
 
                S_StopAllSounds();
 
-               if (cls.state == ca_connected && cls.signon < SIGNONS)
+               if (cls.state == ca_connected)
                {
-                       Con_Printf("reconnecting...\n");
+                       Con_Printf("Server is changing level...\n");
                        MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd);
                        MSG_WriteString(&cls.netcon->message, "new");
                }
@@ -503,7 +526,7 @@ void Host_Reconnect_f (void)
        else
        {
                // netquake uses reconnect on level changes (silly)
-               if (Cmd_Argc() != 1)
+               if (Cmd_Argc(cmd) != 1)
                {
                        Con_Print("reconnect : wait for signon messages again\n");
                        return;
@@ -524,9 +547,9 @@ Host_Connect_f
 User command to connect to server
 =====================
 */
-static void Host_Connect_f (void)
+static void Host_Connect_f(cmd_state_t *cmd)
 {
-       if (Cmd_Argc() < 2)
+       if (Cmd_Argc(cmd) < 2)
        {
                Con_Print("connect <serveraddress> [<key> <value> ...]: connect to a multiplayer game\n");
                return;
@@ -534,7 +557,7 @@ static void Host_Connect_f (void)
        // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
        if(rcon_secure.integer <= 0)
                Cvar_SetQuick(&rcon_password, "");
-       CL_EstablishConnection(Cmd_Argv(1), 2);
+       CL_EstablishConnection(Cmd_Argv(cmd, 1), 2);
 }
 
 
@@ -551,7 +574,7 @@ LOAD / SAVE GAME
 void Host_Savegame_to(prvm_prog_t *prog, const char *name)
 {
        qfile_t *f;
-       int             i, k, l, lightstyles = 64;
+       int             i, k, l, numbuffers, lightstyles = 64;
        char    comment[SAVEGAME_COMMENT_LENGTH+1];
        char    line[MAX_INPUTLINE];
        qboolean isserver;
@@ -581,7 +604,7 @@ void Host_Savegame_to(prvm_prog_t *prog, const char *name)
        else
                dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", prog->name);
        // convert space to _ to make stdio happy
-       // LordHavoc: convert control characters to _ as well
+       // LadyHavoc: convert control characters to _ as well
        for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
                if (ISWHITESPACEORCONTROL(comment[i]))
                        comment[i] = '_';
@@ -641,11 +664,13 @@ void Host_Savegame_to(prvm_prog_t *prog, const char *name)
                        FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
 
        // darkplaces extension - save buffers
-       for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); i++)
+       numbuffers = (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray);
+       for (i = 0; i < numbuffers; i++)
        {
                prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
                if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED))
                {
+                       FS_Printf(f,"sv.buffer %i %i \"string\"\n", i, stringbuffer->flags & STRINGBUFFER_QCFLAGS);
                        for(k = 0; k < stringbuffer->num_strings; k++)
                        {
                                if (!stringbuffer->strings[k])
@@ -696,7 +721,7 @@ void Host_Savegame_to(prvm_prog_t *prog, const char *name)
 Host_Savegame_f
 ===============
 */
-static void Host_Savegame_f (void)
+static void Host_Savegame_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        char    name[MAX_QPATH];
@@ -726,21 +751,21 @@ static void Host_Savegame_f (void)
                }
        }
        else
-               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");
+               Con_Warn("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");
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Print("save <savename> : save a game\n");
                return;
        }
 
-       if (strstr(Cmd_Argv(1), ".."))
+       if (strstr(Cmd_Argv(cmd, 1), ".."))
        {
                Con_Print("Relative pathnames are not allowed.\n");
                return;
        }
 
-       strlcpy (name, Cmd_Argv(1), sizeof (name));
+       strlcpy (name, Cmd_Argv(cmd, 1), sizeof (name));
        FS_DefaultExtension (name, ".sav", sizeof (name));
 
        Host_Savegame_to(prog, name);
@@ -753,7 +778,7 @@ Host_Loadgame_f
 ===============
 */
 
-static void Host_Loadgame_f (void)
+static void Host_Loadgame_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        char filename[MAX_QPATH];
@@ -764,20 +789,19 @@ static void Host_Loadgame_f (void)
        const char *t;
        char *text;
        prvm_edict_t *ent;
-       int i, k;
+       int i, k, numbuffers;
        int entnum;
        int version;
        float spawn_parms[NUM_SPAWN_PARMS];
        prvm_stringbuffer_t *stringbuffer;
-       size_t alloclen;
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Print("load <savename> : load a game\n");
                return;
        }
 
-       strlcpy (filename, Cmd_Argv(1), sizeof(filename));
+       strlcpy (filename, Cmd_Argv(cmd, 1), sizeof(filename));
        FS_DefaultExtension (filename, ".sav", sizeof (filename));
 
        Con_Printf("Loading game from %s...\n", filename);
@@ -786,9 +810,11 @@ static void Host_Loadgame_f (void)
        if (cls.demoplayback)
                CL_Disconnect ();
 
+#ifdef CONFIG_MENU
        // remove menu
        if (key_dest == key_menu || key_dest == key_menu_grabbed)
                MR_ToggleMenu(0);
+#endif
        key_dest = key_game;
 
        cls.demonum = -1;               // stop demo loop in case this fails
@@ -828,7 +854,7 @@ static void Host_Loadgame_f (void)
        COM_ParseToken_Simple(&t, false, false, true);
 // this silliness is so we can load 1.06 save files, which have float skill values
        current_skill = (int)(atof(com_token) + 0.5);
-       Cvar_SetValue ("skill", (float)current_skill);
+       Cvar_SetValue (&cvars_all, "skill", (float)current_skill);
 
        if(developer_entityparsing.integer)
                Con_Printf("Host_Loadgame_f: loading mapname\n");
@@ -844,8 +870,6 @@ static void Host_Loadgame_f (void)
        COM_ParseToken_Simple(&t, false, false, true);
        time = atof(com_token);
 
-       allowcheats = sv_cheats.integer != 0;
-
        if(developer_entityparsing.integer)
                Con_Printf("Host_Loadgame_f: spawning server\n");
 
@@ -932,7 +956,7 @@ static void Host_Loadgame_f (void)
                        PRVM_ED_ParseGlobals (prog, start);
 
                        // restore the autocvar globals
-                       Cvar_UpdateAllAutoCvars();
+                       Cvar_UpdateAllAutoCvars(prog->console_cmd->cvars);
                }
                else
                {
@@ -945,7 +969,7 @@ static void Host_Loadgame_f (void)
                        while (entnum >= prog->max_edicts)
                                PRVM_MEM_IncreaseEdicts(prog);
                        ent = PRVM_EDICT_NUM(entnum);
-                       memset(ent->fields.vp, 0, prog->entityfields * 4);
+                       memset(ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
                        ent->priv.server->free = false;
 
                        if(developer_entityparsing.integer)
@@ -954,7 +978,7 @@ static void Host_Loadgame_f (void)
                        PRVM_ED_ParseEdict (prog, start, ent);
 
                        // link it into the bsp tree
-                       if (!ent->priv.server->free)
+                       if (!ent->priv.server->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax)))
                                SV_LinkEdict(ent);
                }
 
@@ -988,6 +1012,8 @@ static void Host_Loadgame_f (void)
                        memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
                        memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
                        memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
+                       BufStr_Flush(prog);
+
                        while (COM_ParseToken_Simple(&t, false, false, true))
                        {
                                if (!strcmp(com_token, "sv.lightstyles"))
@@ -1023,44 +1049,48 @@ static void Host_Loadgame_f (void)
                                        else
                                                Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
                                }
+                               else if (!strcmp(com_token, "sv.buffer"))
+                               {
+                                       if (COM_ParseToken_Simple(&t, false, false, true))
+                                       {
+                                               i = atoi(com_token);
+                                               if (i >= 0)
+                                               {
+                                                       k = STRINGBUFFER_SAVED;
+                                                       if (COM_ParseToken_Simple(&t, false, false, true))
+                                                               k |= atoi(com_token);
+                                                       if (!BufStr_FindCreateReplace(prog, i, k, "string"))
+                                                               Con_Errorf("failed to create stringbuffer %i\n", i);
+                                               }
+                                               else
+                                                       Con_Printf("unsupported stringbuffer index %i \"%s\"\n", i, com_token);
+                                       }
+                                       else
+                                               Con_Printf("unexpected end of line when parsing sv.buffer (expected buffer index)\n");
+                               }
                                else if (!strcmp(com_token, "sv.bufstr"))
                                {
-                                       COM_ParseToken_Simple(&t, false, false, true);
-                                       i = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false, true);
-                                       k = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false, true);
-                                       stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
-                                       // VorteX: nasty code, cleanup required
-                                       // create buffer at this index
-                                       if(!stringbuffer) 
-                                               stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecordAtIndex(&prog->stringbuffersarray, i);
-                                       if (!stringbuffer)
-                                               Con_Printf("cant write string %i into buffer %i\n", k, i);
+                                       if (!COM_ParseToken_Simple(&t, false, false, true))
+                                               Con_Printf("unexpected end of line when parsing sv.bufstr\n");
                                        else
                                        {
-                                               // code copied from VM_bufstr_set
-                                               // expand buffer
-                                               if (stringbuffer->max_strings <= i)
+                                               i = atoi(com_token);
+                                               stringbuffer = BufStr_FindCreateReplace(prog, i, STRINGBUFFER_SAVED, "string");
+                                               if (stringbuffer)
                                                {
-                                                       char **oldstrings = stringbuffer->strings;
-                                                       stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128);
-                                                       while (stringbuffer->max_strings <= i)
-                                                               stringbuffer->max_strings *= 2;
-                                                       stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0]));
-                                                       if (stringbuffer->num_strings > 0)
-                                                               memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0]));
-                                                       if (oldstrings)
-                                                               Mem_Free(oldstrings);
+                                                       if (COM_ParseToken_Simple(&t, false, false, true))
+                                                       {
+                                                               k = atoi(com_token);
+                                                               if (COM_ParseToken_Simple(&t, false, false, true))
+                                                                       BufStr_Set(prog, stringbuffer, k, com_token);
+                                                               else
+                                                                       Con_Printf("unexpected end of line when parsing sv.bufstr (expected string)\n");
+                                                       }
+                                                       else
+                                                               Con_Printf("unexpected end of line when parsing sv.bufstr (expected strindex)\n");
                                                }
-                                               // allocate string
-                                               stringbuffer->num_strings = max(stringbuffer->num_strings, k + 1);
-                                               if(stringbuffer->strings[k])
-                                                       Mem_Free(stringbuffer->strings[k]);
-                                               stringbuffer->strings[k] = NULL;
-                                               alloclen = strlen(com_token) + 1;
-                                               stringbuffer->strings[k] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
-                                               memcpy(stringbuffer->strings[k], com_token, alloclen);
+                                               else
+                                                       Con_Errorf("failed to create stringbuffer %i \"%s\"\n", i, com_token);
                                        }
                                }       
                                // skip any trailing text or unrecognized commands
@@ -1071,6 +1101,15 @@ static void Host_Loadgame_f (void)
        }
        Mem_Free(text);
 
+       // remove all temporary flagged string buffers (ones created with BufStr_FindCreateReplace)
+       numbuffers = (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray);
+       for (i = 0; i < numbuffers; i++)
+       {
+               if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) )
+                       if (stringbuffer->flags & STRINGBUFFER_TEMP)
+                               BufStr_Del(prog, stringbuffer);
+       }
+
        if(developer_entityparsing.integer)
                Con_Printf("Host_Loadgame_f: finished\n");
 
@@ -1086,8 +1125,8 @@ static void Host_Loadgame_f (void)
 Host_Name_f
 ======================
 */
-cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
-static void Host_Name_f (void)
+cvar_t cl_name = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
+static void Host_Name_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i, j;
@@ -1095,22 +1134,25 @@ static void Host_Name_f (void)
        const char *newNameSource;
        char newName[sizeof(host_client->name)];
 
-       if (Cmd_Argc () == 1)
+       if (Cmd_Argc (cmd) == 1)
        {
-               Con_Printf("name: %s\n", cl_name.string);
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("name: %s\n", cl_name.string);
+               }
                return;
        }
 
-       if (Cmd_Argc () == 2)
-               newNameSource = Cmd_Argv(1);
+       if (Cmd_Argc (cmd) == 2)
+               newNameSource = Cmd_Argv(cmd, 1);
        else
-               newNameSource = Cmd_Args();
+               newNameSource = Cmd_Args(cmd);
 
        strlcpy(newName, newNameSource, sizeof(newName));
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
-               Cvar_Set ("_cl_name", newName);
+               Cvar_Set (&cvars_all, "_cl_name", newName);
                if (strlen(newNameSource) >= sizeof(newName)) // overflowed
                {
                        Con_Printf("Your name is longer than %i chars! It has been truncated.\n", (int) (sizeof(newName) - 1));
@@ -1198,7 +1240,7 @@ static void Host_Name_f (void)
        PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
        if (strcmp(host_client->old_name, host_client->name))
        {
-               if (host_client->spawned)
+               if (host_client->begun)
                        SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
                strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
                // send notification to all clients
@@ -1214,33 +1256,36 @@ static void Host_Name_f (void)
 Host_Playermodel_f
 ======================
 */
-cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz/Xonotic (changed by playermodel command)"};
+cvar_t cl_playermodel = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz/Xonotic (changed by playermodel command)"};
 // the old cl_playermodel in cl_main has been renamed to __cl_playermodel
-static void Host_Playermodel_f (void)
+static void Host_Playermodel_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i, j;
        char newPath[sizeof(host_client->playermodel)];
 
-       if (Cmd_Argc () == 1)
+       if (Cmd_Argc (cmd) == 1)
        {
-               Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
+               }
                return;
        }
 
-       if (Cmd_Argc () == 2)
-               strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
+       if (Cmd_Argc (cmd) == 2)
+               strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
        else
-               strlcpy (newPath, Cmd_Args(), sizeof (newPath));
+               strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
 
        for (i = 0, j = 0;newPath[i];i++)
                if (newPath[i] != '\r' && newPath[i] != '\n')
                        newPath[j++] = newPath[i];
        newPath[j] = 0;
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
-               Cvar_Set ("_cl_playermodel", newPath);
+               Cvar_Set (&cvars_all, "_cl_playermodel", newPath);
                return;
        }
 
@@ -1272,32 +1317,35 @@ static void Host_Playermodel_f (void)
 Host_Playerskin_f
 ======================
 */
-cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz/Xonotic (changed by playerskin command)"};
-static void Host_Playerskin_f (void)
+cvar_t cl_playerskin = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz/Xonotic (changed by playerskin command)"};
+static void Host_Playerskin_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i, j;
        char newPath[sizeof(host_client->playerskin)];
 
-       if (Cmd_Argc () == 1)
+       if (Cmd_Argc (cmd) == 1)
        {
-               Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
+               }
                return;
        }
 
-       if (Cmd_Argc () == 2)
-               strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
+       if (Cmd_Argc (cmd) == 2)
+               strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
        else
-               strlcpy (newPath, Cmd_Args(), sizeof (newPath));
+               strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
 
        for (i = 0, j = 0;newPath[i];i++)
                if (newPath[i] != '\r' && newPath[i] != '\n')
                        newPath[j++] = newPath[i];
        newPath[j] = 0;
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
-               Cvar_Set ("_cl_playerskin", newPath);
+               Cvar_Set (&cvars_all, "_cl_playerskin", newPath);
                return;
        }
 
@@ -1316,7 +1364,7 @@ static void Host_Playerskin_f (void)
        PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
        if (strcmp(host_client->old_skin, host_client->playerskin))
        {
-               //if (host_client->spawned)
+               //if (host_client->begun)
                //      SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
                strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
                /*// send notification to all clients
@@ -1326,23 +1374,23 @@ static void Host_Playerskin_f (void)
        }
 }
 
-static void Host_Version_f (void)
+static void Host_Version_f(cmd_state_t *cmd)
 {
        Con_Printf("Version: %s build %s\n", gamename, buildstring);
 }
 
-static void Host_Say(qboolean teamonly)
+static void Host_Say(cmd_state_t *cmd, qboolean teamonly)
 {
        prvm_prog_t *prog = SVVM_prog;
        client_t *save;
        int j, quoted;
        const char *p1;
        char *p2;
-       // LordHavoc: long say messages
+       // LadyHavoc: long say messages
        char text[1024];
        qboolean fromServer = false;
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                if (cls.state == ca_dedicated)
                {
@@ -1351,18 +1399,18 @@ static void Host_Say(qboolean teamonly)
                }
                else
                {
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                        return;
                }
        }
 
-       if (Cmd_Argc () < 2)
+       if (Cmd_Argc (cmd) < 2)
                return;
 
        if (!teamplay.integer)
                teamonly = false;
 
-       p1 = Cmd_Args();
+       p1 = Cmd_Args(cmd);
        quoted = false;
        if (*p1 == '\"')
        {
@@ -1400,19 +1448,19 @@ static void Host_Say(qboolean teamonly)
 }
 
 
-static void Host_Say_f(void)
+static void Host_Say_f(cmd_state_t *cmd)
 {
-       Host_Say(false);
+       Host_Say(cmd, false);
 }
 
 
-static void Host_Say_Team_f(void)
+static void Host_Say_Team_f(cmd_state_t *cmd)
 {
-       Host_Say(true);
+       Host_Say(cmd, true);
 }
 
 
-static void Host_Tell_f(void)
+static void Host_Tell_f(cmd_state_t *cmd)
 {
        const char *playername_start = NULL;
        size_t playername_length = 0;
@@ -1420,21 +1468,21 @@ static void Host_Tell_f(void)
        client_t *save;
        int j;
        const char *p1, *p2;
-       char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
+       char text[MAX_INPUTLINE]; // LadyHavoc: FIXME: temporary buffer overflow fix (was 64)
        qboolean fromServer = false;
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                if (cls.state == ca_dedicated)
                        fromServer = true;
                else
                {
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                        return;
                }
        }
 
-       if (Cmd_Argc () < 2)
+       if (Cmd_Argc (cmd) < 2)
                return;
 
        // note this uses the chat prefix \001
@@ -1445,7 +1493,7 @@ static void Host_Tell_f(void)
        else
                dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
 
-       p1 = Cmd_Args();
+       p1 = Cmd_Args(cmd);
        p2 = p1 + strlen(p1);
        // remove the target name
        while (p1 < p2 && *p1 == ' ')
@@ -1546,8 +1594,8 @@ static void Host_Tell_f(void)
 Host_Color_f
 ==================
 */
-cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
-static void Host_Color(int changetop, int changebottom)
+cvar_t cl_color = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
+static void Host_Color(cmd_state_t *cmd, int changetop, int changebottom)
 {
        prvm_prog_t *prog = SVVM_prog;
        int top, bottom, playercolor;
@@ -1559,7 +1607,7 @@ static void Host_Color(int changetop, int changebottom)
 
        top &= 15;
        bottom &= 15;
-       // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
+       // LadyHavoc: allowing skin colormaps 14 and 15 by commenting this out
        //if (top > 13)
        //      top = 13;
        //if (bottom > 13)
@@ -1567,7 +1615,7 @@ static void Host_Color(int changetop, int changebottom)
 
        playercolor = top*16 + bottom;
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                Cvar_SetValueQuick(&cl_color, playercolor);
                return;
@@ -1579,7 +1627,7 @@ static void Host_Color(int changetop, int changebottom)
        if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
        {
                Con_DPrint("Calling SV_ChangeTeam\n");
-               prog->globals.generic[OFS_PARM0] = playercolor;
+               prog->globals.fp[OFS_PARM0] = playercolor;
                PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
                prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
@@ -1603,80 +1651,114 @@ static void Host_Color(int changetop, int changebottom)
        }
 }
 
-static void Host_Color_f(void)
+static void Host_Color_f(cmd_state_t *cmd)
 {
        int             top, bottom;
 
-       if (Cmd_Argc() == 1)
+       if (Cmd_Argc(cmd) == 1)
        {
-               Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
-               Con_Print("color <0-15> [0-15]\n");
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
+                       Con_Print("color <0-15> [0-15]\n");
+               }
                return;
        }
 
-       if (Cmd_Argc() == 2)
-               top = bottom = atoi(Cmd_Argv(1));
+       if (Cmd_Argc(cmd) == 2)
+               top = bottom = atoi(Cmd_Argv(cmd, 1));
        else
        {
-               top = atoi(Cmd_Argv(1));
-               bottom = atoi(Cmd_Argv(2));
+               top = atoi(Cmd_Argv(cmd, 1));
+               bottom = atoi(Cmd_Argv(cmd, 2));
        }
-       Host_Color(top, bottom);
+       Host_Color(cmd, top, bottom);
 }
 
-static void Host_TopColor_f(void)
+static void Host_TopColor_f(cmd_state_t *cmd)
 {
-       if (Cmd_Argc() == 1)
+       if (Cmd_Argc(cmd) == 1)
        {
-               Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
-               Con_Print("topcolor <0-15>\n");
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
+                       Con_Print("topcolor <0-15>\n");
+               }
                return;
        }
 
-       Host_Color(atoi(Cmd_Argv(1)), -1);
+       Host_Color(cmd, atoi(Cmd_Argv(cmd, 1)), -1);
 }
 
-static void Host_BottomColor_f(void)
+static void Host_BottomColor_f(cmd_state_t *cmd)
 {
-       if (Cmd_Argc() == 1)
+       if (Cmd_Argc(cmd) == 1)
        {
-               Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
-               Con_Print("bottomcolor <0-15>\n");
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
+                       Con_Print("bottomcolor <0-15>\n");
+               }
                return;
        }
 
-       Host_Color(-1, atoi(Cmd_Argv(1)));
+       Host_Color(cmd, -1, atoi(Cmd_Argv(cmd, 1)));
 }
 
-cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
-static void Host_Rate_f(void)
+cvar_t cl_rate = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
+cvar_t cl_rate_burstsize = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate_burstsize", "1024", "internal storage cvar for current rate control burst size (changed by rate_burstsize command)"};
+static void Host_Rate_f(cmd_state_t *cmd)
 {
        int rate;
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
-               Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
-               Con_Print("rate <bytespersecond>\n");
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
+                       Con_Print("rate <bytespersecond>\n");
+               }
                return;
        }
 
-       rate = atoi(Cmd_Argv(1));
+       rate = atoi(Cmd_Argv(cmd, 1));
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
-               Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
+               Cvar_SetValue (&cvars_all, "_cl_rate", max(NET_MINRATE, rate));
                return;
        }
 
        host_client->rate = rate;
 }
+static void Host_Rate_BurstSize_f(cmd_state_t *cmd)
+{
+       int rate_burstsize;
+
+       if (Cmd_Argc(cmd) != 2)
+       {
+               Con_Printf("\"rate_burstsize\" is \"%i\"\n", cl_rate_burstsize.integer);
+               Con_Print("rate_burstsize <bytes>\n");
+               return;
+       }
+
+       rate_burstsize = atoi(Cmd_Argv(cmd, 1));
+
+       if (cmd->source == src_command)
+       {
+               Cvar_SetValue (&cvars_all, "_cl_rate_burstsize", rate_burstsize);
+               return;
+       }
+
+       host_client->rate_burstsize = rate_burstsize;
+}
 
 /*
 ==================
 Host_Kill_f
 ==================
 */
-static void Host_Kill_f (void)
+static void Host_Kill_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
@@ -1696,14 +1778,15 @@ static void Host_Kill_f (void)
 Host_Pause_f
 ==================
 */
-static void Host_Pause_f (void)
+static void Host_Pause_f(cmd_state_t *cmd)
 {
-       if (cmd_source == src_command)
+       void (*print) (const char *fmt, ...);
+       if (cmd->source == src_command)
        {
                // if running a client, try to send over network so the pause is handled by the server
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -1713,9 +1796,9 @@ static void Host_Pause_f (void)
 
        if (!pausable.integer)
        {
-               if (cmd_source == src_client)
+               if (cmd->source == src_client)
                {
-                       if(cls.state == ca_dedicated || host_client == &svs.clients[0]) // non-admin
+                       if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin
                        {
                                print("Pause not allowed.\n");
                                return;
@@ -1724,7 +1807,12 @@ static void Host_Pause_f (void)
        }
        
        sv.paused ^= 1;
-       SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
+       if (cmd->source != src_command)
+               SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
+       else if(*(sv_adminnick.string))
+               SV_BroadcastPrintf("%s %spaused the game\n", sv_adminnick.string, sv.paused ? "" : "un");
+       else
+               SV_BroadcastPrintf("%s %spaused the game\n", hostname.string, sv.paused ? "" : "un");
        // send notification to all clients
        MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
        MSG_WriteByte(&sv.reliable_datagram, sv.paused);
@@ -1733,30 +1821,33 @@ static void Host_Pause_f (void)
 /*
 ======================
 Host_PModel_f
-LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
-LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
+LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
+LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
 ======================
 */
-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)"};
-static void Host_PModel_f (void)
+cvar_t cl_pmodel = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
+static void Host_PModel_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i;
 
-       if (Cmd_Argc () == 1)
+       if (Cmd_Argc (cmd) == 1)
        {
-               Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
+               if (cmd->source == src_command)
+               {
+                       Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
+               }
                return;
        }
-       i = atoi(Cmd_Argv(1));
+       i = atoi(Cmd_Argv(cmd, 1));
 
-       if (cmd_source == src_command)
+       if (cmd->source == src_command)
        {
                if (cl_pmodel.integer == i)
                        return;
-               Cvar_SetValue ("_cl_pmodel", i);
+               Cvar_SetValue (&cvars_all, "_cl_pmodel", i);
                if (cls.state == ca_connected)
-                       Cmd_ForwardToServer ();
+                       Cmd_ForwardToServer_f(cmd);
                return;
        }
 
@@ -1771,13 +1862,14 @@ static void Host_PModel_f (void)
 Host_PreSpawn_f
 ==================
 */
-static void Host_PreSpawn_f (void)
+static void Host_PreSpawn_f(cmd_state_t *cmd)
 {
-       if (host_client->spawned)
+       if (host_client->prespawned)
        {
-               Con_Print("prespawn not valid -- already spawned\n");
+               Con_Print("prespawn not valid -- already prespawned\n");
                return;
        }
+       host_client->prespawned = true;
 
        if (host_client->netconnection)
        {
@@ -1796,25 +1888,31 @@ static void Host_PreSpawn_f (void)
 Host_Spawn_f
 ==================
 */
-static void Host_Spawn_f (void)
+static void Host_Spawn_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i;
        client_t *client;
        int stats[MAX_CL_STATS];
 
+       if (!host_client->prespawned)
+       {
+               Con_Print("Spawn not valid -- not yet prespawned\n");
+               return;
+       }
        if (host_client->spawned)
        {
                Con_Print("Spawn not valid -- already spawned\n");
                return;
        }
+       host_client->spawned = true;
 
        // reset name change timer again because they might want to change name
        // again in the first 5 seconds after connecting
        host_client->nametime = 0;
 
-       // LordHavoc: moved this above the QC calls at FrikaC's request
-       // LordHavoc: commented this out
+       // LadyHavoc: moved this above the QC calls at FrikaC's request
+       // LadyHavoc: commented this out
        //if (host_client->netconnection)
        //      SZ_Clear (&host_client->netconnection->message);
 
@@ -1933,11 +2031,21 @@ static void Host_Spawn_f (void)
 Host_Begin_f
 ==================
 */
-static void Host_Begin_f (void)
+static void Host_Begin_f(cmd_state_t *cmd)
 {
-       host_client->spawned = true;
+       if (!host_client->spawned)
+       {
+               Con_Print("Begin not valid -- not yet spawned\n");
+               return;
+       }
+       if (host_client->begun)
+       {
+               Con_Print("Begin not valid -- already begun\n");
+               return;
+       }
+       host_client->begun = true;
 
-       // LordHavoc: note: this code also exists in SV_DropClient
+       // LadyHavoc: note: this code also exists in SV_DropClient
        if (sv.loadgame)
        {
                int i;
@@ -1962,7 +2070,7 @@ Host_Kick_f
 Kicks a user off of the server
 ==================
 */
-static void Host_Kick_f (void)
+static void Host_Kick_f(cmd_state_t *cmd)
 {
        const char *who;
        const char *message = NULL;
@@ -1975,9 +2083,9 @@ static void Host_Kick_f (void)
 
        save = host_client;
 
-       if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
+       if (Cmd_Argc(cmd) > 2 && strcmp(Cmd_Argv(cmd, 1), "#") == 0)
        {
-               i = (int)(atof(Cmd_Argv(2)) - 1);
+               i = (int)(atof(Cmd_Argv(cmd, 2)) - 1);
                if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
                        return;
                byNumber = true;
@@ -1988,14 +2096,14 @@ static void Host_Kick_f (void)
                {
                        if (!host_client->active)
                                continue;
-                       if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
+                       if (strcasecmp(host_client->name, Cmd_Argv(cmd, 1)) == 0)
                                break;
                }
        }
 
        if (i < svs.maxclients)
        {
-               if (cmd_source == src_command)
+               if (cmd->source == src_command)
                {
                        if (cls.state == ca_dedicated)
                                who = "Console";
@@ -2009,16 +2117,16 @@ static void Host_Kick_f (void)
                if (host_client == save)
                        return;
 
-               if (Cmd_Argc() > 2)
+               if (Cmd_Argc(cmd) > 2)
                {
-                       message = Cmd_Args();
+                       message = Cmd_Args(cmd);
                        COM_ParseToken_Simple(&message, false, false, true);
                        if (byNumber)
                        {
                                message++;                                                      // skip the #
                                while (*message == ' ')                         // skip white space
                                        message++;
-                               message += strlen(Cmd_Argv(2)); // skip the number
+                               message += strlen(Cmd_Argv(cmd, 2));    // skip the number
                        }
                        while (*message && *message == ' ')
                                message++;
@@ -2046,20 +2154,20 @@ DEBUGGING TOOLS
 Host_Give_f
 ==================
 */
-static void Host_Give_f (void)
+static void Host_Give_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        const char *t;
        int v;
 
-       if (!allowcheats)
+       if (!sv_cheats.integer)
        {
                SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
                return;
        }
 
-       t = Cmd_Argv(1);
-       v = atoi (Cmd_Argv(2));
+       t = Cmd_Argv(cmd, 1);
+       v = atoi (Cmd_Argv(cmd, 2));
 
        switch (t[0])
        {
@@ -2074,7 +2182,7 @@ static void Host_Give_f (void)
        case '8':
        case '9':
                // MED 01/04/97 added hipnotic give stuff
-               if (gamemode == GAME_HIPNOTIC)
+               if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
                {
                        if (t[0] == '6')
                        {
@@ -2189,7 +2297,7 @@ static prvm_edict_t       *FindViewthing(prvm_prog_t *prog)
 Host_Viewmodel_f
 ==================
 */
-static void Host_Viewmodel_f (void)
+static void Host_Viewmodel_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
@@ -2201,14 +2309,14 @@ static void Host_Viewmodel_f (void)
        e = FindViewthing(prog);
        if (e)
        {
-               m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
+               m = Mod_ForName (Cmd_Argv(cmd, 1), false, true, NULL);
                if (m && m->loaded && m->Draw)
                {
                        PRVM_serveredictfloat(e, frame) = 0;
                        cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
                }
                else
-                       Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
+                       Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(cmd, 1));
        }
 }
 
@@ -2217,7 +2325,7 @@ static void Host_Viewmodel_f (void)
 Host_Viewframe_f
 ==================
 */
-static void Host_Viewframe_f (void)
+static void Host_Viewframe_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
@@ -2232,7 +2340,7 @@ static void Host_Viewframe_f (void)
        {
                m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
 
-               f = atoi(Cmd_Argv(1));
+               f = atoi(Cmd_Argv(cmd, 1));
                if (f >= m->numframes)
                        f = m->numframes-1;
 
@@ -2254,7 +2362,7 @@ static void PrintFrameName (dp_model_t *m, int frame)
 Host_Viewnext_f
 ==================
 */
-static void Host_Viewnext_f (void)
+static void Host_Viewnext_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
@@ -2281,7 +2389,7 @@ static void Host_Viewnext_f (void)
 Host_Viewprev_f
 ==================
 */
-static void Host_Viewprev_f (void)
+static void Host_Viewprev_f(cmd_state_t *cmd)
 {
        prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
@@ -2317,14 +2425,14 @@ DEMO LOOP CONTROL
 Host_Startdemos_f
 ==================
 */
-static void Host_Startdemos_f (void)
+static void Host_Startdemos_f(cmd_state_t *cmd)
 {
        int             i, c;
 
        if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
                return;
 
-       c = Cmd_Argc() - 1;
+       c = Cmd_Argc(cmd) - 1;
        if (c > MAX_DEMOS)
        {
                Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS);
@@ -2333,9 +2441,9 @@ static void Host_Startdemos_f (void)
        Con_DPrintf("%i demo(s) in loop\n", c);
 
        for (i=1 ; i<c+1 ; i++)
-               strlcpy (cls.demos[i-1], Cmd_Argv(i), sizeof (cls.demos[i-1]));
+               strlcpy (cls.demos[i-1], Cmd_Argv(cmd, i), sizeof (cls.demos[i-1]));
 
-       // LordHavoc: clear the remaining slots
+       // LadyHavoc: clear the remaining slots
        for (;i <= MAX_DEMOS;i++)
                cls.demos[i-1][0] = 0;
 
@@ -2356,13 +2464,13 @@ Host_Demos_f
 Return to looping demos
 ==================
 */
-static void Host_Demos_f (void)
+static void Host_Demos_f(cmd_state_t *cmd)
 {
        if (cls.state == ca_dedicated)
                return;
        if (cls.demonum == -1)
                cls.demonum = 1;
-       CL_Disconnect_f ();
+       CL_Disconnect_f (cmd);
        CL_NextDemo ();
 }
 
@@ -2373,7 +2481,7 @@ Host_Stopdemo_f
 Return to looping demos
 ==================
 */
-static void Host_Stopdemo_f (void)
+static void Host_Stopdemo_f(cmd_state_t *cmd)
 {
        if (!cls.demoplayback)
                return;
@@ -2381,7 +2489,7 @@ static void Host_Stopdemo_f (void)
        Host_ShutdownServer ();
 }
 
-static void Host_SendCvar_f (void)
+static void Host_SendCvar_f(cmd_state_t *cmd)
 {
        int             i;
        cvar_t  *c;
@@ -2389,13 +2497,13 @@ static void Host_SendCvar_f (void)
        client_t *old;
        char vabuf[1024];
 
-       if(Cmd_Argc() != 2)
+       if(Cmd_Argc(cmd) != 2)
                return;
-       cvarname = Cmd_Argv(1);
+       cvarname = Cmd_Argv(cmd, 1);
        if (cls.state == ca_connected)
        {
-               c = Cvar_FindVar(cvarname);
-               // LordHavoc: if there is no such cvar or if it is private, send a
+               c = Cvar_FindVar(&cvars_all, cvarname, CVAR_CLIENT | CVAR_SERVER);
+               // LadyHavoc: if there is no such cvar or if it is private, send a
                // reply indicating that it has no value
                if(!c || (c->flags & CVAR_PRIVATE))
                        Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "sentcvar %s", cvarname));
@@ -2420,11 +2528,11 @@ static void Host_SendCvar_f (void)
        host_client = old;
 }
 
-static void MaxPlayers_f(void)
+static void MaxPlayers_f(cmd_state_t *cmd)
 {
        int n;
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients_next);
                return;
@@ -2436,15 +2544,15 @@ static void MaxPlayers_f(void)
                Con_Print("It will be changed on next server startup (\"map\" command).\n");
        }
 
-       n = atoi(Cmd_Argv(1));
+       n = atoi(Cmd_Argv(cmd, 1));
        n = bound(1, n, MAX_SCOREBOARD);
        Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
 
        svs.maxclients_next = n;
        if (n == 1)
-               Cvar_Set ("deathmatch", "0");
+               Cvar_Set (&cvars_all, "deathmatch", "0");
        else
-               Cvar_Set ("deathmatch", "1");
+               Cvar_Set (&cvars_all, "deathmatch", "1");
 }
 
 /*
@@ -2454,13 +2562,17 @@ Host_PQRcon_f
 ProQuake rcon support
 =====================
 */
-static void Host_PQRcon_f (void)
+static void Host_PQRcon_f(cmd_state_t *cmd)
 {
        int n;
        const char *e;
-       lhnetaddress_t to;
        lhnetsocket_t *mysocket;
-       char peer_address[64];
+
+       if (Cmd_Argc(cmd) == 1)
+       {
+               Con_Printf("%s: Usage: %s command\n", Cmd_Argv(cmd, 0), Cmd_Argv(cmd, 0));
+               return;
+       }
 
        if (!rcon_password.string || !rcon_password.string[0] || rcon_secure.integer > 0)
        {
@@ -2472,9 +2584,7 @@ static void Host_PQRcon_f (void)
        n = e ? e-rcon_password.string : (int)strlen(rcon_password.string);
 
        if (cls.netcon)
-       {
-               InfoString_GetValue(cls.userinfo, "*ip", peer_address, sizeof(peer_address));
-       }
+               cls.rcon_address = cls.netcon->peeraddress;
        else
        {
                if (!rcon_address.string[0])
@@ -2482,10 +2592,9 @@ static void Host_PQRcon_f (void)
                        Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
                        return;
                }
-               strlcpy(peer_address, rcon_address.string, strlen(rcon_address.string)+1);
+               LHNETADDRESS_FromString(&cls.rcon_address, rcon_address.string, sv_netport.integer);
        }
-       LHNETADDRESS_FromString(&to, peer_address, sv_netport.integer);
-       mysocket = NetConn_ChooseClientSocketForAddress(&to);
+       mysocket = NetConn_ChooseClientSocketForAddress(&cls.rcon_address);
        if (mysocket)
        {
                sizebuf_t buf;
@@ -2496,9 +2605,9 @@ static void Host_PQRcon_f (void)
                MSG_WriteByte(&buf, CCREQ_RCON);
                SZ_Write(&buf, (const unsigned char*)rcon_password.string, n);
                MSG_WriteByte(&buf, 0); // terminate the (possibly partial) string
-               MSG_WriteString(&buf, Cmd_Args());
+               MSG_WriteString(&buf, Cmd_Args(cmd));
                StoreBigLong(buf.data, NETFLAG_CTL | (buf.cursize & NETFLAG_LENGTH_MASK));
-               NetConn_Write(mysocket, buf.data, buf.cursize, &to);
+               NetConn_Write(mysocket, buf.data, buf.cursize, &cls.rcon_address);
                SZ_Clear(&buf);
        }
 }
@@ -2515,13 +2624,17 @@ Host_Rcon_f
   an unconnected command.
 =====================
 */
-static void Host_Rcon_f (void) // credit: taken from QuakeWorld
+static void Host_Rcon_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        int i, n;
        const char *e;
-       lhnetaddress_t to;
        lhnetsocket_t *mysocket;
-       char vabuf[1024];
+
+       if (Cmd_Argc(cmd) == 1)
+       {
+               Con_Printf("%s: Usage: %s command\n", Cmd_Argv(cmd, 0), Cmd_Argv(cmd, 0));
+               return;
+       }
 
        if (!rcon_password.string || !rcon_password.string[0])
        {
@@ -2533,7 +2646,7 @@ static void Host_Rcon_f (void) // credit: taken from QuakeWorld
        n = e ? e-rcon_password.string : (int)strlen(rcon_password.string);
 
        if (cls.netcon)
-               to = cls.netcon->peeraddress;
+               cls.rcon_address = cls.netcon->peeraddress;
        else
        {
                if (!rcon_address.string[0])
@@ -2541,13 +2654,13 @@ static void Host_Rcon_f (void) // credit: taken from QuakeWorld
                        Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n");
                        return;
                }
-               LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer);
+               LHNETADDRESS_FromString(&cls.rcon_address, rcon_address.string, sv_netport.integer);
        }
-       mysocket = NetConn_ChooseClientSocketForAddress(&to);
-       if (mysocket && Cmd_Args()[0])
+       mysocket = NetConn_ChooseClientSocketForAddress(&cls.rcon_address);
+       if (mysocket && Cmd_Args(cmd)[0])
        {
                // simply put together the rcon packet and send it
-               if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer > 1)
+               if(Cmd_Argv(cmd, 0)[0] == 's' || rcon_secure.integer > 1)
                {
                        if(cls.rcon_commands[cls.rcon_ringpos][0])
                        {
@@ -2559,13 +2672,13 @@ static void Host_Rcon_f (void) // credit: taken from QuakeWorld
                        }
                        for (i = 0;i < MAX_RCONS;i++)
                                if(cls.rcon_commands[i][0])
-                                       if (!LHNETADDRESS_Compare(&to, &cls.rcon_addresses[i]))
+                                       if (!LHNETADDRESS_Compare(&cls.rcon_address, &cls.rcon_addresses[i]))
                                                break;
                        ++cls.rcon_trying;
                        if(i >= MAX_RCONS)
-                               NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", &to); // otherwise we'll request the challenge later
-                       strlcpy(cls.rcon_commands[cls.rcon_ringpos], Cmd_Args(), sizeof(cls.rcon_commands[cls.rcon_ringpos]));
-                       cls.rcon_addresses[cls.rcon_ringpos] = to;
+                               NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", &cls.rcon_address); // otherwise we'll request the challenge later
+                       strlcpy(cls.rcon_commands[cls.rcon_ringpos], Cmd_Args(cmd), sizeof(cls.rcon_commands[cls.rcon_ringpos]));
+                       cls.rcon_addresses[cls.rcon_ringpos] = cls.rcon_address;
                        cls.rcon_timeout[cls.rcon_ringpos] = realtime + rcon_secure_challengetimeout.value;
                        cls.rcon_ringpos = (cls.rcon_ringpos + 1) % MAX_RCONS;
                }
@@ -2573,18 +2686,21 @@ static void Host_Rcon_f (void) // credit: taken from QuakeWorld
                {
                        char buf[1500];
                        char argbuf[1500];
-                       dpsnprintf(argbuf, sizeof(argbuf), "%ld.%06d %s", (long) time(NULL), (int) (rand() % 1000000), Cmd_Args());
+                       dpsnprintf(argbuf, sizeof(argbuf), "%ld.%06d %s", (long) time(NULL), (int) (rand() % 1000000), Cmd_Args(cmd));
                        memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24);
-                       if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, n))
+                       if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, (int)strlen(argbuf), (unsigned char *) rcon_password.string, n))
                        {
                                buf[40] = ' ';
                                strlcpy(buf + 41, argbuf, sizeof(buf) - 41);
-                               NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to);
+                               NetConn_Write(mysocket, buf, 41 + (int)strlen(buf + 41), &cls.rcon_address);
                        }
                }
                else
                {
-                       NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377rcon %.*s %s", n, rcon_password.string, Cmd_Args()), &to);
+                       char buf[1500];
+                       memcpy(buf, "\377\377\377\377", 4);
+                       dpsnprintf(buf+4, sizeof(buf)-4, "rcon %.*s %s",  n, rcon_password.string, Cmd_Args(cmd));
+                       NetConn_WriteString(mysocket, buf, &cls.rcon_address);
                }
        }
 }
@@ -2598,24 +2714,24 @@ user <name or userid>
 Dump userdata / masterdata for a user
 ====================
 */
-static void Host_User_f (void) // credit: taken from QuakeWorld
+static void Host_User_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        int             uid;
        int             i;
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Printf ("Usage: user <username / userid>\n");
                return;
        }
 
-       uid = atoi(Cmd_Argv(1));
+       uid = atoi(Cmd_Argv(cmd, 1));
 
        for (i = 0;i < cl.maxclients;i++)
        {
                if (!cl.scores[i].name[0])
                        continue;
-               if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1)))
+               if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(cmd, 1)))
                {
                        InfoString_Print(cl.scores[i].qw_userinfo);
                        return;
@@ -2631,7 +2747,7 @@ Host_Users_f
 Dump userids for all current players
 ====================
 */
-static void Host_Users_f (void) // credit: taken from QuakeWorld
+static void Host_Users_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        int             i;
        int             c;
@@ -2659,16 +2775,16 @@ Sent by server when serverinfo changes
 ==================
 */
 // TODO: shouldn't this be a cvar instead?
-static void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
+static void Host_FullServerinfo_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        char temp[512];
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Printf ("usage: fullserverinfo <complete info string>\n");
                return;
        }
 
-       strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo));
+       strlcpy (cl.qw_serverinfo, Cmd_Argv(cmd, 1), sizeof(cl.qw_serverinfo));
        InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp));
        cl.qw_teamplay = atoi(temp);
 }
@@ -2681,45 +2797,50 @@ Allow clients to change userinfo
 ==================
 Casey was here :)
 */
-static void Host_FullInfo_f (void) // credit: taken from QuakeWorld
+static void Host_FullInfo_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        char key[512];
        char value[512];
-       char *o;
        const char *s;
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Printf ("fullinfo <complete info string>\n");
                return;
        }
 
-       s = Cmd_Argv(1);
+       s = Cmd_Argv(cmd, 1);
        if (*s == '\\')
                s++;
        while (*s)
        {
-               o = key;
-               while (*s && *s != '\\')
-                       *o++ = *s++;
-               *o = 0;
-
+               size_t len = strcspn(s, "\\");
+               if (len >= sizeof(key)) {
+                       len = sizeof(key) - 1;
+               }
+               strlcpy(key, s, len + 1);
+               s += len;
                if (!*s)
                {
                        Con_Printf ("MISSING VALUE\n");
                        return;
                }
+               ++s; // Skip over backslash.
 
-               o = value;
-               s++;
-               while (*s && *s != '\\')
-                       *o++ = *s++;
-               *o = 0;
-
-               if (*s)
-                       s++;
+               len = strcspn(s, "\\");
+               if (len >= sizeof(value)) {
+                       len = sizeof(value) - 1;
+               }
+               strlcpy(value, s, len + 1);
 
                CL_SetInfo(key, value, false, false, false, false);
+
+               s += len;
+               if (!*s)
+               {
+                       break;
+               }
+               ++s; // Skip over backslash.
        }
 }
 
@@ -2730,19 +2851,19 @@ CL_SetInfo_f
 Allow clients to change userinfo
 ==================
 */
-static void Host_SetInfo_f (void) // credit: taken from QuakeWorld
+static void Host_SetInfo_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
-       if (Cmd_Argc() == 1)
+       if (Cmd_Argc(cmd) == 1)
        {
                InfoString_Print(cls.userinfo);
                return;
        }
-       if (Cmd_Argc() != 3)
+       if (Cmd_Argc(cmd) != 3)
        {
                Con_Printf ("usage: setinfo [ <key> <value> ]\n");
                return;
        }
-       CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false);
+       CL_SetInfo(Cmd_Argv(cmd, 1), Cmd_Argv(cmd, 2), true, false, false, false);
 }
 
 /*
@@ -2754,7 +2875,7 @@ packet <destination> <contents>
 Contents allows \n escape character
 ====================
 */
-static void Host_Packet_f (void) // credit: taken from QuakeWorld
+static void Host_Packet_f(cmd_state_t *cmd) // credit: taken from QuakeWorld
 {
        char send[2048];
        int i, l;
@@ -2763,19 +2884,19 @@ static void Host_Packet_f (void) // credit: taken from QuakeWorld
        lhnetaddress_t address;
        lhnetsocket_t *mysocket;
 
-       if (Cmd_Argc() != 3)
+       if (Cmd_Argc(cmd) != 3)
        {
                Con_Printf ("packet <destination> <contents>\n");
                return;
        }
 
-       if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer))
+       if (!LHNETADDRESS_FromString (&address, Cmd_Argv(cmd, 1), sv_netport.integer))
        {
                Con_Printf ("Bad address\n");
                return;
        }
 
-       in = Cmd_Argv(2);
+       in = Cmd_Argv(cmd, 2);
        out = send+4;
        send[0] = send[1] = send[2] = send[3] = -1;
 
@@ -2827,7 +2948,7 @@ Host_Pings_f
 Send back ping and packet loss update for all current players to this player
 ====================
 */
-void Host_Pings_f (void)
+static void Host_Pings_f(cmd_state_t *cmd)
 {
        int             i, j, ping, packetloss, movementloss;
        char temp[128];
@@ -2879,17 +3000,17 @@ void Host_Pings_f (void)
                MSG_WriteString(&host_client->netconnection->message, "\n");
 }
 
-static void Host_PingPLReport_f(void)
+static void Host_PingPLReport_f(cmd_state_t *cmd)
 {
        char *errbyte;
        int i;
-       int l = Cmd_Argc();
+       int l = Cmd_Argc(cmd);
        if (l > cl.maxclients)
                l = cl.maxclients;
        for (i = 0;i < l;i++)
        {
-               cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2));
-               cl.scores[i].qw_packetloss = strtol(Cmd_Argv(1+i*2+1), &errbyte, 0);
+               cl.scores[i].qw_ping = atoi(Cmd_Argv(cmd, 1+i*2));
+               cl.scores[i].qw_packetloss = strtol(Cmd_Argv(cmd, 1+i*2+1), &errbyte, 0);
                if(errbyte && *errbyte == ',')
                        cl.scores[i].qw_movementloss = atoi(errbyte + 1);
                else
@@ -2908,93 +3029,137 @@ void Host_InitCommands (void)
 {
        dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
 
-       Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information");
-       Cmd_AddCommand ("quit", Host_Quit_f, "quit the game");
-       Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)");
-       Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)");
-       Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)");
-       Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
-       Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory");
-       Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level");
-       Cmd_AddCommand ("restart", Host_Restart_f, "restart current level");
-       Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
-       Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname");
-       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)");
-       Cmd_AddCommand ("version", Host_Version_f, "print engine version");
-       Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server");
-       Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server");
-       Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server");
-       Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly");
-       Cmd_AddCommand_WithClientCommand ("pause", Host_Pause_f, Host_Pause_f, "pause the game (if the server allows pausing)");
-       Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name");
-       Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server");
-       Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file");
-       Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file");
-
-       Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
-       Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
-       Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
-
-       Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
-       Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
-       Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
-       Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
-
-       Cvar_RegisterVariable (&cl_name);
-       Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name");
-       Cvar_RegisterVariable (&cl_color);
-       Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors");
-       Cvar_RegisterVariable (&cl_rate);
-       Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed");
-       Cvar_RegisterVariable (&cl_pmodel);
-       Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "(Nehahra-only) change your player model choice");
-
-       // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first)
-       Cvar_RegisterVariable (&cl_playermodel);
-       Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model");
-       Cvar_RegisterVariable (&cl_playerskin);
-       Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number");
-
-       Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)");
-       Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
-       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)");
-       Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
-
-       Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
-
-       Cvar_RegisterVariable (&rcon_password);
-       Cvar_RegisterVariable (&rcon_address);
-       Cvar_RegisterVariable (&rcon_secure);
-       Cvar_RegisterVariable (&rcon_secure_challengetimeout);
-       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); note: if rcon_secure is set, client and server clocks must be synced e.g. via NTP");
-       Cmd_AddCommand ("srcon", 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); this always works as if rcon_secure is set; note: client and server clocks must be synced e.g. via NTP");
-       Cmd_AddCommand ("pqrcon", Host_PQRcon_f, "sends a command to a proquake 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)");
-       Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
-       Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard");
-       Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
-       Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
-       Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo");
-       Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
-       Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
-       Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
-
-       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)");
-       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)");
-
-       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)");
-       Cvar_RegisterVariable (&r_fixtrans_auto);
-
-       Cvar_RegisterVariable (&team);
-       Cvar_RegisterVariable (&skin);
-       Cvar_RegisterVariable (&noaim);
-
+       Cvar_RegisterVariable(&cl_name);
+       Cvar_RegisterVariable(&cl_color);
+       Cvar_RegisterVariable(&cl_rate);
+       Cvar_RegisterVariable(&cl_rate_burstsize);
+       Cvar_RegisterVariable(&cl_pmodel);
+       Cvar_RegisterVariable(&cl_playermodel);
+       Cvar_RegisterVariable(&cl_playerskin);
+       Cvar_RegisterVariable(&rcon_password);
+       Cvar_RegisterVariable(&rcon_address);
+       Cvar_RegisterVariable(&rcon_secure);
+       Cvar_RegisterVariable(&rcon_secure_challengetimeout);
+       Cvar_RegisterVariable(&r_fixtrans_auto);
+       Cvar_RegisterVariable(&team);
+       Cvar_RegisterVariable(&skin);
+       Cvar_RegisterVariable(&noaim);
        Cvar_RegisterVariable(&sv_cheats);
+       Cvar_RegisterCallback(&sv_cheats, Host_DisableCheats_c);
        Cvar_RegisterVariable(&sv_adminnick);
        Cvar_RegisterVariable(&sv_status_privacy);
        Cvar_RegisterVariable(&sv_status_show_qcstatus);
        Cvar_RegisterVariable(&sv_namechangetimer);
+
+       // client commands - this includes server commands because the client can host a server, so they must exist
+       Cmd_AddCommand(&cmd_client, "quit", Host_Quit_f, "quit the game");
+       Cmd_AddCommand(&cmd_client, "status", Host_Status_f, "print server status information");
+       Cmd_AddCommand(&cmd_client, "map", Host_Map_f, "kick everyone off the server and start a new level");
+       Cmd_AddCommand(&cmd_client, "restart", Host_Restart_f, "restart current level");
+       Cmd_AddCommand(&cmd_client, "changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
+       Cmd_AddCommand(&cmd_client, "version", Host_Version_f, "print engine version");
+       Cmd_AddCommand(&cmd_client, "say", Host_Say_f, "send a chat message to everyone on the server");
+       Cmd_AddCommand(&cmd_client, "tell", Host_Tell_f, "send a chat message to only one person on the server");
+       Cmd_AddCommand(&cmd_client, "pause", Host_Pause_f, "pause the game (if the server allows pausing)");
+       Cmd_AddCommand(&cmd_client, "kick", Host_Kick_f, "kick a player off the server by number or name");
+       Cmd_AddCommand(&cmd_client, "ping", Host_Ping_f, "print ping times of all players on the server");
+       Cmd_AddCommand(&cmd_client, "load", Host_Loadgame_f, "load a saved game file");
+       Cmd_AddCommand(&cmd_client, "save", Host_Savegame_f, "save the game to a file");
+       Cmd_AddCommand(&cmd_client, "viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_client, "viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_client, "viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_client, "viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_client, "maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
+       Cmd_AddCommand(&cmd_client, "user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
+       Cmd_AddCommand(&cmd_client, "users", Host_Users_f, "prints additional information about all players on the scoreboard");
+
+       // dedicated server commands
+       Cmd_AddCommand(&cmd_server, "quit", Host_Quit_f, "quit the game");
+       Cmd_AddCommand(&cmd_server, "status", Host_Status_f, "print server status information");
+       Cmd_AddCommand(&cmd_server, "map", Host_Map_f, "kick everyone off the server and start a new level");
+       Cmd_AddCommand(&cmd_server, "restart", Host_Restart_f, "restart current level");
+       Cmd_AddCommand(&cmd_server, "changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients");
+       Cmd_AddCommand(&cmd_server, "version", Host_Version_f, "print engine version");
+       Cmd_AddCommand(&cmd_server, "say", Host_Say_f, "send a chat message to everyone on the server");
+       Cmd_AddCommand(&cmd_server, "tell", Host_Tell_f, "send a chat message to only one person on the server");
+       Cmd_AddCommand(&cmd_server, "pause", Host_Pause_f, "pause the game (if the server allows pausing)");
+       Cmd_AddCommand(&cmd_server, "kick", Host_Kick_f, "kick a player off the server by number or name");
+       Cmd_AddCommand(&cmd_server, "ping", Host_Ping_f, "print ping times of all players on the server");
+       Cmd_AddCommand(&cmd_server, "load", Host_Loadgame_f, "load a saved game file");
+       Cmd_AddCommand(&cmd_server, "save", Host_Savegame_f, "save the game to a file");
+       Cmd_AddCommand(&cmd_server, "viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_server, "viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_server, "viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_server, "viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level");
+       Cmd_AddCommand(&cmd_server, "maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
+       Cmd_AddCommand(&cmd_server, "user", Host_User_f, "prints additional information about a player number or name on the scoreboard");
+       Cmd_AddCommand(&cmd_server, "users", Host_Users_f, "prints additional information about all players on the scoreboard");
+
+       // commands that do not have automatic forwarding from cmd_client, these are internal details of the network protocol and not of interest to users (if they know what they are doing they can still use a generic "cmd prespawn" or similar)
+       Cmd_AddCommand(&cmd_serverfromclient, "prespawn", Host_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
+       Cmd_AddCommand(&cmd_serverfromclient, "spawn", Host_Spawn_f, "internal use - signon 2 (client has sent player information, and is asking server to send scoreboard rankings)");
+       Cmd_AddCommand(&cmd_serverfromclient, "begin", Host_Begin_f, "internal use - signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)");
+       Cmd_AddCommand(&cmd_serverfromclient, "pings", Host_Pings_f, "internal use - command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)");
+
+       Cmd_AddCommand(&cmd_serverfromclient, "status", Host_Status_f, "print server status information");
+       Cmd_AddCommand(&cmd_serverfromclient, "god", Host_God_f, "god mode (invulnerability)");
+       Cmd_AddCommand(&cmd_serverfromclient, "notarget", Host_Notarget_f, "notarget mode (monsters do not see you)");
+       Cmd_AddCommand(&cmd_serverfromclient, "fly", Host_Fly_f, "fly mode (flight)");
+       Cmd_AddCommand(&cmd_serverfromclient, "noclip", Host_Noclip_f, "noclip mode (flight without collisions, move through walls)");
+       Cmd_AddCommand(&cmd_serverfromclient, "give", Host_Give_f, "alter inventory");
+       Cmd_AddCommand(&cmd_serverfromclient, "say", Host_Say_f, "send a chat message to everyone on the server");
+       Cmd_AddCommand(&cmd_serverfromclient, "say_team", Host_Say_Team_f, "send a chat message to your team on the server");
+       Cmd_AddCommand(&cmd_serverfromclient, "tell", Host_Tell_f, "send a chat message to only one person on the server");
+       Cmd_AddCommand(&cmd_serverfromclient, "kill", Host_Kill_f, "die instantly");
+       Cmd_AddCommand(&cmd_serverfromclient, "pause", Host_Pause_f, "pause the game (if the server allows pausing)");
+       Cmd_AddCommand(&cmd_serverfromclient, "ping", Host_Ping_f, "print ping times of all players on the server");
+       Cmd_AddCommand(&cmd_serverfromclient, "name", Host_Name_f, "change your player name");
+       Cmd_AddCommand(&cmd_serverfromclient, "color", Host_Color_f, "change your player shirt and pants colors");
+       Cmd_AddCommand(&cmd_serverfromclient, "rate", Host_Rate_f, "change your network connection speed");
+       Cmd_AddCommand(&cmd_serverfromclient, "rate_burstsize", Host_Rate_BurstSize_f, "change your network connection speed");
+       Cmd_AddCommand(&cmd_serverfromclient, "pmodel", Host_PModel_f, "(Nehahra-only) change your player model choice");
+       Cmd_AddCommand(&cmd_serverfromclient, "playermodel", Host_Playermodel_f, "change your player model");
+       Cmd_AddCommand(&cmd_serverfromclient, "playerskin", Host_Playerskin_f, "change your player skin number");
+
+       // client commands that require a connection and are simply forwarded to server
+       Cmd_AddCommand(&cmd_client, "god", Cmd_ForwardToServer_f, "god mode (invulnerability)");
+       Cmd_AddCommand(&cmd_client, "notarget", Cmd_ForwardToServer_f, "notarget mode (monsters do not see you)");
+       Cmd_AddCommand(&cmd_client, "fly", Cmd_ForwardToServer_f, "fly mode (flight)");
+       Cmd_AddCommand(&cmd_client, "noclip", Cmd_ForwardToServer_f, "noclip mode (flight without collisions, move through walls)");
+       Cmd_AddCommand(&cmd_client, "give", Cmd_ForwardToServer_f, "alter inventory");
+       Cmd_AddCommand(&cmd_client, "say_team", Cmd_ForwardToServer_f, "send a chat message to your team on the server");
+       Cmd_AddCommand(&cmd_client, "kill", Cmd_ForwardToServer_f, "die instantly");
+
+       Cmd_AddCommand(&cmd_client, "connect", Host_Connect_f, "connect to a server by IP address or hostname");
+       Cmd_AddCommand(&cmd_client, "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)");
+       Cmd_AddCommand(&cmd_client, "startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)");
+       Cmd_AddCommand(&cmd_client, "demos", Host_Demos_f, "restart looping demos defined by the last startdemos command");
+       Cmd_AddCommand(&cmd_client, "stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos");
+       Cmd_AddCommand(&cmd_client, "sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
+       Cmd_AddCommand(&cmd_client, "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); note: if rcon_secure is set, client and server clocks must be synced e.g. via NTP");
+       Cmd_AddCommand(&cmd_client, "srcon", 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); this always works as if rcon_secure is set; note: client and server clocks must be synced e.g. via NTP");
+       Cmd_AddCommand(&cmd_client, "pqrcon", Host_PQRcon_f, "sends a command to a proquake 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)");
+       Cmd_AddCommand(&cmd_client, "fullinfo", Host_FullInfo_f, "allows client to modify their userinfo");
+       Cmd_AddCommand(&cmd_client, "setinfo", Host_SetInfo_f, "modifies your userinfo");
+       Cmd_AddCommand(&cmd_client, "packet", Host_Packet_f, "send a packet to the specified address:port containing a text string");
+       Cmd_AddCommand(&cmd_client, "topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color");
+       Cmd_AddCommand(&cmd_client, "bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color");
+       Cmd_AddCommand(&cmd_client, "fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)");
+
+       // client commands that also exist as cmd_serverfromclient and are often forwarded
+       Cmd_AddCommand(&cmd_client, "name", Host_Name_f, "change your player name");
+       Cmd_AddCommand(&cmd_client, "color", Host_Color_f, "change your player shirt and pants colors");
+       Cmd_AddCommand(&cmd_client, "rate", Host_Rate_f, "change your network connection speed");
+       Cmd_AddCommand(&cmd_client, "rate_burstsize", Host_Rate_BurstSize_f, "change your network connection speed");
+       Cmd_AddCommand(&cmd_client, "pmodel", Host_PModel_f, "(Nehahra-only) change your player model choice");
+       Cmd_AddCommand(&cmd_client, "playermodel", Host_Playermodel_f, "change your player model");
+       Cmd_AddCommand(&cmd_client, "playerskin", Host_Playerskin_f, "change your player skin number");
+
+       // commands that are only sent by server to client for execution
+       Cmd_AddCommand(&cmd_client, "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)");
+       Cmd_AddCommand(&cmd_client, "fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string");
 }
 
-void Host_NoOperation_f(void)
+void Host_NoOperation_f(cmd_state_t *cmd)
 {
 }