Index: src/settings.cpp
===================================================================
--- src/settings.cpp	(revision 13639)
+++ src/settings.cpp	(working copy)
@@ -1462,6 +1462,7 @@
 	if (strcmp(_settings_client.network.rcon_password, "*") == 0) {
 		_settings_client.network.rcon_password[0] = '\0';
 	}
+	InvalidateWindow(WC_GAME_OPTIONS, 0);
 
 	return 0;
 }
@@ -2181,6 +2182,11 @@
 	if (!_networking || (_networking && _network_server)) {
 		return DoCommandP(0, index, value, NULL, CMD_CHANGE_PATCH_SETTING);
 	}
+	if (_networking && !_network_server && _settings_client.network.rcon_password[0] != '\0') {
+		char patch_rcon_command[70];
+		sprintf(patch_rcon_command, "patch %s %d", _patch_settings[index].desc.name, value);
+		NetworkClientSendRcon(_settings_client.network.rcon_password, patch_rcon_command);
+	}
 	return false;
 }
 
Index: src/toolbar_gui.cpp
===================================================================
--- src/toolbar_gui.cpp	(revision 13639)
+++ src/toolbar_gui.cpp	(working copy)
@@ -41,6 +41,7 @@
 
 #include "network/network.h"
 #include "network/network_gui.h"
+#include "network/network_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -173,8 +174,13 @@
 
 static void ToolbarPauseClick(Window *w)
 {
-	if (_networking && !_network_server) return; // only server can pause the game
-
+	if (!(_networking && (_network_server || _settings_client.network.rcon_password[0] != \0))) return; // you can only pause the game if you have the rcon password or are the server
+	if (_networking && !_network_server && _settings_client.network.rcon_password[0] != '\0') {
+		NetworkClientSendRcon(_settings_client.network.rcon_password, (_pause_game ? "unpause" : "pause"));
+		SndPlayFx(SND_15_BEEP);
+	}
+	
+	if (_networking && !_network_server) return; // only server can pause the game using this command
 	if (DoCommandP(0, _pause_game ? 0 : 1, 0, NULL, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
 }
 
@@ -890,7 +896,6 @@
 struct MainToolbarWindow : Window {
 	MainToolbarWindow(const WindowDesc *desc) : Window(desc)
 	{
-		this->SetWidgetDisabledState(TBN_PAUSE, _networking && !_network_server); // if not server, disable pause button
 		this->SetWidgetDisabledState(TBN_FASTFORWARD, _networking); // if networking, disable fast-forward button
 
 		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
@@ -906,6 +911,7 @@
 		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB2);
 		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
 
+		this->SetWidgetDisabledState(TBN_PAUSE, !(_networking && (_network_server || _settings_client.network.rcon_password[0] != \0))); // if not server, disable pause button
 		/* If spectator, disable all construction buttons
 		* ie : Build road, rail, ships, airports and landscaping
 		* Since enabled state is the default, just disable when needed */
Index: src/lang/english.txt
===================================================================
--- src/lang/english.txt	(revision 13639)
+++ src/lang/english.txt	(working copy)
@@ -1583,6 +1583,8 @@
 STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL                             :Speak to all
 STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY                         :Speak to company
 STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT                          :Private message
+STR_NETWORK_CLIENTLIST_MOVE                                     :Move
+STR_NETWORK_CLIENTLIST_MUTE                                     :Mute
 
 
 STR_NETWORK_SEND                                                :{BLACK}Send
@@ -3570,3 +3572,17 @@
 STR_NOISE_IN_TOWN                                               :{BLACK}Noise limit in town: {ORANGE}{COMMA}{BLACK}  max: {ORANGE}{COMMA}
 STR_STATION_NOISE                                               :{BLACK}Noise generated: {GOLD}{COMMA}
 ########
+
+############ move player gui
+STR_MOVE_PLAYER_CAPTION                                         :{WHITE}Move client to...
+STR_MOVE_PLAYER_SPECTATORS                                      :{WHITE}Spectators
+STR_MOVE_PLAYER_TOOLTIP                                         :{BLACK}Click here to move the client to this company
+########
+
+############ mute player gui
+STR_MUTE_PLAYER_CAPTION                                         :{WHITE}Mute client
+STR_MUTE_PLAYER_ALL                                                 :{WHITE}All
+STR_MUTE_PLAYER_TEAM                                              :{WHITE}Team
+STR_MUTE_PLAYER_PRIVATE                                         :{WHITE}Private
+STR_MUTE_PLAYER_TOOLTIP                                         :{BLACK}Click here to mute the client for this chattype
+########
\ No newline at end of file
Index: src/settings_gui.cpp
===================================================================
--- src/settings_gui.cpp	(revision 13639)
+++ src/settings_gui.cpp	(working copy)
@@ -803,7 +803,11 @@
 			bool disabled = false;
 
 			// We do not allow changes of some items when we are a client in a networkgame
-			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
+			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) {
+					if (!_network_server && _settings_client.network.rcon_password[0] == '\0') {
+						editable = false;
+					}
+				}
 			if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
 			if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
 
@@ -865,7 +869,12 @@
 				sd = page->entries[btn].setting;
 
 				/* return if action is only active in network, or only settable by server */
-				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
+				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) {
+					if (!_network_server && _settings_client.network.rcon_password[0] == '\0') {
+						return;
+					}
+				}
+
 				if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
 				if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
 
Index: src/console_cmds.cpp
===================================================================
--- src/console_cmds.cpp	(revision 13639)
+++ src/console_cmds.cpp	(working copy)
@@ -592,6 +592,48 @@
 	return true;
 }
 
+DEF_CONSOLE_CMD(ConMoveClient)
+{
+	NetworkClientInfo *ci;
+	uint16 index;
+	PlayerID new_player;
+
+	if (argc < 2) {
+		IConsoleHelp("Move a player to another company. Usage: move <client-id> [<company-id>]");
+		IConsoleHelp("For client-id see 'clients', company-id must be between 1 and 8, ommit if moving to spectators");
+		return true;
+	}
+
+	index = atoi(argv[1]);
+	new_player = (argc == 3) ? (PlayerID)(atoi(argv[2])-1) : PLAYER_SPECTATOR; 
+	
+	if (index == NETWORK_SERVER_INDEX) {
+		IConsoleError("Silly boy, you can not move the server!");
+		return true;
+	}
+
+	ci = NetworkFindClientInfoFromIndex(index);
+	if (ci == NULL) {
+		IConsoleError("Invalid client");
+		return true;
+	}
+
+	if (!IsValidPlayer(new_player) && new_player != PLAYER_SPECTATOR) {
+		IConsoleError("Company does not exist, see command 'players'.");
+		return true;
+	}
+
+	/* safe to update, update first the actual client, then all clients */
+	ci->client_playas = new_player;
+	NetworkServerSendMove(index, new_player);
+	NetworkUpdateClientInfo(index);
+
+	IConsolePrintF(CC_DEFAULT, "[move] client %d to company %d.", index, min(new_player+1, PLAYER_SPECTATOR));
+	if (!_network_dedicated) InvalidateWindow(WC_MOVE_PLAYER, 0);
+	if (!_network_dedicated) InvalidateWindow(WC_CLIENT_LIST, 0);
+	return true;
+}
+
 DEF_CONSOLE_CMD(ConResetCompany)
 {
 	const Player *p;
@@ -707,6 +749,49 @@
 	return true;
 }
 
+DEF_CONSOLE_CMD(ConMute)
+{
+	NetworkClientInfo *ci;
+	
+	if (argc != 3 && argc != 2) {
+		IConsoleHelp("Mute a specific client. Usage: 'mute <clientid> <mutetype>'");
+		IConsoleHelp("Types are 1.broadcast 2.team and 3.private");
+		return true;
+	}
+	uint16 client_index = atoi(argv[1]);
+	
+	ci = NetworkFindClientInfoFromIndex(client_index);
+	if (ci == NULL) {
+		IConsoleError("Invalid client");
+		return true;
+	}
+	
+	if (client_index == NETWORK_SERVER_INDEX) {
+		IConsoleError("Silly boy, you can not mute the server");
+		return true;
+	}
+
+	if (argc == 3) {
+		switch (atoi(argv[2]) - 1) {
+			case DESTTYPE_BROADCAST:
+				ToggleBit(ci->mute, 1);
+				break;
+			case DESTTYPE_TEAM:
+				ToggleBit(ci->mute, 2);
+				break;
+			case DESTTYPE_CLIENT:
+				ToggleBit(ci->mute, 3);
+				break;
+			default: return false;
+		}
+	}
+	IConsolePrintF(CC_DEFAULT, "Current muted status of client %d: %s %s %s", client_index, (HasBit(ci->mute, 1) ? "public" : ""), (HasBit(ci->mute, 2) ? "team" : ""), (HasBit(ci->mute, 3) ? "private" : ""));
+	NetworkServerSendMuteStatus(client_index);
+	if (!_network_dedicated) InvalidateWindow(WC_MUTE_PLAYER, 0);
+	return true;
+	
+}
+
 #endif /* ENABLE_NETWORK */
 
 /* ******************************** */
@@ -1411,6 +1496,8 @@
 	IConsoleCmdRegister("rcon",            ConRcon);
 	IConsoleCmdHookAdd("rcon",             ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
 
+	IConsoleCmdRegister("move",            ConMoveClient);
+	IConsoleCmdHookAdd("move",             ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
 	IConsoleCmdRegister("reset_company",   ConResetCompany);
 	IConsoleCmdHookAdd("reset_company",    ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
 	IConsoleAliasRegister("clean_company", "reset_company %A");
@@ -1427,6 +1514,8 @@
 	IConsoleCmdHookAdd("pause",            ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
 	IConsoleCmdRegister("unpause",         ConUnPauseGame);
 	IConsoleCmdHookAdd("unpause",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
+	IConsoleCmdRegister("mute",         ConMute);
+	IConsoleCmdHookAdd("mute",          ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
 
 	/*** Networking variables ***/
 	IConsoleVarStringRegister("company_pw",      NULL, 0, "Set a password for your company, so no one without the correct password can join. Use '*' to clear the password");
Index: src/window_type.h
===================================================================
--- src/window_type.h	(revision 13639)
+++ src/window_type.h	(working copy)
@@ -94,6 +94,8 @@
 	WC_BUILD_SIGNAL,
 	WC_COMPANY_PASSWORD_WINDOW,
 	WC_OSK,
+	WC_MOVE_PLAYER,
+	WC_MUTE_PLAYER,
 
 	WC_INVALID = 0xFFFF
 };
Index: src/network/network_type.h
===================================================================
--- src/network/network_type.h	(revision 13639)
+++ src/network/network_type.h	(working copy)
@@ -57,6 +57,7 @@
 	uint32 client_ip;                               ///< IP-address of the client (so he can be banned)
 	Date join_date;                                 ///< Gamedate the player has joined
 	char unique_id[NETWORK_UNIQUE_ID_LENGTH];       ///< Every play sends an unique id so we can indentify him
+	byte mute;                                       ///< Contains the mute status
 };
 
 enum NetworkPasswordType {
Index: src/network/core/tcp.h
===================================================================
--- src/network/core/tcp.h	(revision 13639)
+++ src/network/core/tcp.h	(working copy)
@@ -55,6 +55,7 @@
 	PACKET_CLIENT_RCON,
 	PACKET_SERVER_CHECK_NEWGRFS,
 	PACKET_CLIENT_NEWGRFS_CHECKED,
+	PACKET_CLIENT_MOVE,
 	PACKET_END                   ///< Must ALWAYS be on the end of this list!! (period)
 };
 
Index: src/network/network_func.h
===================================================================
--- src/network/network_func.h	(revision 13639)
+++ src/network/network_func.h	(working copy)
@@ -53,9 +53,11 @@
 NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip);
 const char* GetPlayerIP(const NetworkClientInfo *ci);
 
+void NetworkServerSendMove(uint16 client_index, PlayerID new_player);
 void NetworkServerSendRcon(uint16 client_index, ConsoleColour colour_code, const char *string);
 void NetworkServerSendError(uint16 client_index, NetworkErrorCode error);
 void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index);
+void NetworkServerSendMuteStatus(uint16 client_index);
 
 #define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX)
 
Index: src/network/network_server.cpp
===================================================================
--- src/network/network_server.cpp	(revision 13639)
+++ src/network/network_server.cpp	(working copy)
@@ -58,6 +58,7 @@
 		p->Send_uint8 (ci->client_playas);
 		p->Send_string(ci->client_name);
 		p->Send_string(ci->unique_id);
+		p->Send_uint8(ci->mute);
 
 		cs->Send_Packet(p);
 	}
@@ -599,6 +600,17 @@
 	cs->Send_Packet(p);
 }
 
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(NetworkTCPSocketHandler *cs, uint16 client_index, PlayerID new_player)
+{
+	Packet *p = NetworkSend_Init(PACKET_CLIENT_MOVE);
+
+	DEBUG(net, 0, "[move] client %d to player %d", client_index, min(new_player+1, PLAYER_SPECTATOR));
+
+	p->Send_uint16(client_index);
+	p->Send_uint8(new_player);
+	cs->Send_Packet(p);
+}
+
 // **********
 // Receiving functions
 //   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkTCPSocketHandler *cs, Packet *p
@@ -1061,10 +1073,12 @@
 void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index)
 {
 	NetworkTCPSocketHandler *cs;
-	const NetworkClientInfo *ci, *ci_own, *ci_to;
+	const NetworkClientInfo *ci, *ci_own, *ci_to, *ci_from;
+	ci_from = NetworkFindClientInfoFromIndex(from_index);
 
 	switch (desttype) {
 	case DESTTYPE_CLIENT:
+		if (ci_from != NULL && HasBit(ci_from->mute, 3)) break;
 		/* Are we sending to the server? */
 		if (dest == NETWORK_SERVER_INDEX) {
 			ci = NetworkFindClientInfoFromIndex(from_index);
@@ -1101,6 +1115,7 @@
 	case DESTTYPE_TEAM: {
 		bool show_local = true; // If this is false, the message is already displayed
 														// on the client who did sent it.
+		if (ci_from != NULL && HasBit(ci_from->mute, 2)) break;
 		/* Find all clients that belong to this player */
 		ci_to = NULL;
 		FOR_ALL_CLIENTS(cs) {
@@ -1145,6 +1160,7 @@
 		DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
 		/* fall-through to next case */
 	case DESTTYPE_BROADCAST:
+		if (ci_from != NULL && HasBit(ci_from->mute, 1)) break;
 		FOR_ALL_CLIENTS(cs) {
 			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
 		}
@@ -1284,6 +1300,7 @@
 	RECEIVE_COMMAND(PACKET_CLIENT_RCON),
 	NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/
 	RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED),
+	NULL /*PACKET_CLIENT_MOVE,*/
 };
 
 // If this fails, check the array above with network_data.h
@@ -1676,6 +1693,11 @@
 	}
 }
 
+void NetworkServerSendMove(uint16 client_index, PlayerID new_player)
+{
+	SEND_COMMAND(PACKET_CLIENT_MOVE)(NetworkFindClientStateFromIndex(client_index), client_index, new_player);
+}
+
 void NetworkServerSendRcon(uint16 client_index, ConsoleColour colour_code, const char *string)
 {
 	SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(client_index), colour_code, string);
@@ -1696,4 +1718,10 @@
 	}
 	return false;
 }
+
+void NetworkServerSendMuteStatus(uint16 client_index) 
+{
+	if (NetworkFindClientStateFromIndex(client_index)->status != STATUS_ACTIVE) return;
+	NetworkUpdateClientInfo(client_index);
+}
 #endif /* ENABLE_NETWORK */
Index: src/network/network_server.h
===================================================================
--- src/network/network_server.h	(revision 13639)
+++ src/network/network_server.h	(working copy)
@@ -13,6 +13,7 @@
 DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN);
 DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME);
 DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkTCPSocketHandler *cs, uint16 color, const char *command);
+DEF_SERVER_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(NetworkTCPSocketHandler *cs, uint16 client_index, uint8 player_index);
 
 bool NetworkServer_ReadPackets(NetworkTCPSocketHandler *cs);
 void NetworkServer_Tick(bool send_frame);
Index: src/network/network_client.cpp
===================================================================
--- src/network/network_client.cpp	(revision 13639)
+++ src/network/network_client.cpp	(working copy)
@@ -7,6 +7,7 @@
 #include "../stdafx.h"
 #include "../debug.h"
 #include "../openttd.h"
+#include "../gfx_func.h"
 #include "network_internal.h"
 #include "core/tcp.h"
 #include "network_client.h"
@@ -27,7 +28,6 @@
 #include "../player_base.h"
 #include "../player_gui.h"
 #include "../rev.h"
-
 #include "table/strings.h"
 
 // This file handles all the client-commands
@@ -396,6 +396,7 @@
 //  which is always an unique number on a server.
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
 {
+	const Player *player;
 	NetworkClientInfo *ci;
 	uint16 index = p->Recv_uint16();
 	PlayerID playas = (Owner)p->Recv_uint8();
@@ -404,6 +405,7 @@
 
 	p->Recv_string(name, sizeof(name));
 	p->Recv_string(unique_id, sizeof(unique_id));
+	byte muted = (byte)p->Recv_uint8();
 
 	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
 
@@ -416,14 +418,34 @@
 			// Client name changed, display the change
 			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", name);
 		} else if (playas != ci->client_playas) {
-			// The player changed from client-player..
-			// Do not display that for now
+			/* Client has been moved to another company or to spectator, show a message. */
+			if (ci->client_playas != PLAYER_NEW_COMPANY && ci->client_playas != PLAYER_INACTIVE_CLIENT) {
+				/* if not valid player, force spectator, else check player exists */
+				if (!IsValidPlayer(playas)) {
+					playas = PLAYER_SPECTATOR;
+				} else {
+					/* only if it's a valid player, actually get the player and check it */
+					player = GetPlayer(playas);
+					if (!player->is_active) {
+						playas = PLAYER_SPECTATOR;
+					}
+				}
+				
+				if (playas == PLAYER_SPECTATOR || playas > MAX_PLAYERS) {
+					NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, ci->client_name, "'%s' Moved To Spectators", ci->client_name);
+				} else {
+					NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, ci->client_name, "'%s' Moved To Company #%d", ci->client_name, playas+1);
+				}
+			}
 		}
 
 		ci->client_playas = playas;
 		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
+		ci->mute = muted;
 
 		InvalidateWindow(WC_CLIENT_LIST, 0);
+		InvalidateWindow(WC_MOVE_PLAYER, 0);
+		InvalidateWindow(WC_MUTE_PLAYER, 0);
 
 		return NETWORK_RECV_STATUS_OKAY;
 	}
@@ -857,6 +879,51 @@
 	return NETWORK_RECV_STATUS_OKAY;
 }
 
+DEF_CLIENT_RECEIVE_COMMAND(PACKET_CLIENT_MOVE)
+{
+	const Player *player;
+	uint16 client_index;
+	PlayerID player_index;
+	
+	/* Nothing more in this packet... */
+	client_index = p->Recv_uint16();
+	player_index = (Owner)p->Recv_uint8();
+	
+	if (client_index == 0) {
+		/* deffinately an invalide client id, debug message and do nothing. */
+		DEBUG(net, 0, "[move] received client index = 0");
+		return NETWORK_RECV_STATUS_OKAY;
+	}
+	
+	const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index);
+	/* Just make sure we do not try to use a client_index that does not exist */
+	if (ci != NULL) {
+		/* if not valid player, force spectator, else check player exists */
+		if (!IsValidPlayer(player_index)) {
+			player_index = PLAYER_SPECTATOR;
+		} else {
+			/* only if it's a valid player, actually get the player and check it */
+			player = GetPlayer(player_index);
+			if (!player->is_active) {
+				player_index = PLAYER_SPECTATOR;
+			}
+		}
+		
+		if (client_index == _network_own_client_index) {
+			/* this packet is actually for this client... apply the new player_index */
+			DEBUG(net, 0, "[move] client %d to player %d", client_index, min(player_index+1, PLAYER_SPECTATOR));
+			
+			_network_playas = player_index;
+			SetLocalPlayer(player_index);
+			
+			/* Disable any buttons in any windows the client is now not supposed to get to, and do it fast. */
+			/* If this is not done fast enough, it can cause the client to be kicked or have an assert! */
+			MarkWholeScreenDirty();
+		}
+	}
+	
+	return NETWORK_RECV_STATUS_OKAY;
+}
 
 
 // The layout for the receive-functions by the client
@@ -901,6 +968,7 @@
 	NULL, /*PACKET_CLIENT_RCON,*/
 	RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS),
 	NULL, /*PACKET_CLIENT_NEWGRFS_CHECKED,*/
+	RECEIVE_COMMAND(PACKET_CLIENT_MOVE),
 };
 
 // If this fails, check the array above with network_data.h
Index: src/network/network_gui.cpp
===================================================================
--- src/network/network_gui.cpp	(revision 13639)
+++ src/network/network_gui.cpp	(working copy)
@@ -31,6 +31,9 @@
 #include "../widgets/dropdown_func.h"
 #include "../querystring_gui.h"
 #include "../sortlist_type.h"
+#include "../player_base.h"
+#include "../debug.h"
+#include "../console_func.h"
 
 #include "table/strings.h"
 #include "../table/sprites.h"
@@ -43,6 +46,10 @@
 static void ShowNetworkStartServerWindow();
 static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
 extern void SwitchMode(int new_mode);
+static void ShowMovePlayerWindow();
+byte _current_move_window_client;
+byte _current_mute_window_client;
+static void ShowMutePlayerWindow();
 
 static const StringID _connection_types_dropdown[] = {
 	STR_NETWORK_LAN_INTERNET,
@@ -1218,12 +1225,28 @@
 // Here we start to define the options out of the menu
 static void ClientList_Kick(byte client_no)
 {
-	if (client_no < MAX_PLAYERS)
-		SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
+	char kick_rcon_command[15];
+	if (client_no < MAX_PLAYERS) {
+	
+		if (_network_server) {
+			SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED);
+		}
+		else if (_networking && _settings_client.network.rcon_password[0] != '\0') {
+			sprintf(kick_rcon_command, "kick %d", DEREF_CLIENT_INFO(DEREF_CLIENT(client_no))->client_index);
+			NetworkClientSendRcon(_settings_client.network.rcon_password, kick_rcon_command);
+		}
+	}
 }
 
 static void ClientList_Ban(byte client_no)
 {
+	char ban_rcon_command[15];
+	if (_networking && _settings_client.network.rcon_password[0] != '\0') {
+		sprintf(ban_rcon_command, "ban %d", DEREF_CLIENT_INFO(DEREF_CLIENT(client_no))->client_index);
+		NetworkClientSendRcon(_settings_client.network.rcon_password, ban_rcon_command);
+		return;
+	}
+	
 	uint32 ip = NetworkFindClientInfo(client_no)->client_ip;
 
 	for (uint i = 0; i < lengthof(_network_ban_list); i++) {
@@ -1264,6 +1287,18 @@
 	ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
 }
 
+static void ClientList_Move(byte client_no)
+{
+	_current_move_window_client = client_no;
+	ShowMovePlayerWindow();
+}
+
+static void ClientList_Mute(byte client_no)
+{
+	_current_mute_window_client = client_no;
+	ShowMutePlayerWindow();
+}
+
 static void ClientList_None(byte client_no)
 {
 	/* No action ;) */
@@ -1286,20 +1321,22 @@
 		 * Watch is, max 50 chars long!
 		 */
 
-		const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
+		const NetworkClientInfo *ci = NetworkFindClientInfo(client_no), *own_ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
 		int i = 0;
-		if (_network_own_client_index != ci->client_index) {
+		if (_network_own_client_index != ci->client_index && !HasBit(own_ci->mute, 3)) {
 			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
 			this->proc[i++] = &ClientList_SpeakToClient;
 		}
 
-		if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
+		if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR && !HasBit(own_ci->mute, 2)) {
 			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
 			this->proc[i++] = &ClientList_SpeakToCompany;
 		}
-		GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
-		this->proc[i++] = &ClientList_SpeakToAll;
+		if (!HasBit(own_ci->mute, 1)) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_SpeakToAll;
+		}
 
 		if (_network_own_client_index != ci->client_index) {
 			/* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
@@ -1308,15 +1345,27 @@
 				this->proc[i++] = &ClientList_GiveMoney;
 			}
 		}
+		
 
+
 		/* A server can kick clients (but not himself) */
-		if (_network_server && _network_own_client_index != ci->client_index) {
+		if ((_network_server && _network_own_client_index != ci->client_index) || (_settings_client.network.rcon_password[0] != '\0' && ci->client_index != NETWORK_SERVER_INDEX && ci->client_index != _network_own_client_index)) {
 			GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
 			this->proc[i++] = &ClientList_Kick;
 
 			sprintf(this->action[i],"Ban"); // XXX GetString?
 			this->proc[i++] = &ClientList_Ban;
 		}
+		
+		if ((_network_server || (_settings_client.network.rcon_password[0] != 0)) && ci->client_index != NETWORK_SERVER_INDEX) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_MOVE, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_Move;
+		}
+		
+		if (ci->client_index != NETWORK_SERVER_INDEX && _network_own_client_index != ci->client_index && (_network_server || (_settings_client.network.rcon_password[0] != 0))) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_MUTE, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_Mute;
+		}
 
 		if (i == 0) {
 			GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
@@ -1876,6 +1925,7 @@
 void ShowNetworkChatQueryWindow(DestType type, int dest)
 {
 	DeleteWindowById(WC_SEND_NETWORK_MSG, 0);
+	if (HasBit(NetworkFindClientInfoFromIndex(_network_own_client_index)->mute, type + 1)) return;
 	new NetworkChatWindow (&_chat_window_desc, type, dest);
 }
 
@@ -1983,9 +2033,171 @@
 
 void ShowNetworkCompanyPasswordWindow(Window *parent)
 {
-	DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
+	DeleteWindowById(WC_MOVE_PLAYER, 0);
 
 	new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
 }
 
+enum MovePlayerWindowWidgets {
+	MPW_CLOSE,
+	MPW_CAPTION,
+	MPW_BACKGROUND,
+	MPW_SPECTATORS,
+	MPW_FIRST_COMPANY,
+	MPW_LAST_COMPANY = 11
+};
+
+struct MovePlayerWindow : Window {
+	MovePlayerWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		const Player *p;
+
+
+		this->DrawWidgets();
+		NetworkClientInfo *move_ci = DEREF_CLIENT_INFO(DEREF_CLIENT(_current_move_window_client));
+
+		FOR_ALL_PLAYERS(p) {
+			if (!p->is_active) continue;
+
+			DrawPlayerIcon(p->index, 4, 18 + (p->index+1) * 12);
+
+			SetDParam(0, p->index);
+			SetDParam(1, p->index);
+			
+			DrawString(21, 17 + (p->index+1) * 12, STR_7021, TC_WHITE);
+			if (move_ci->client_playas == p->index) this->LowerWidget(p->index + MPW_FIRST_COMPANY);
+		}
+		if (move_ci->client_playas == PLAYER_SPECTATOR) this->LowerWidget(MPW_SPECTATORS);
+		DrawString(21, 17, STR_MOVE_PLAYER_SPECTATORS, TC_WHITE);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (!IsInsideMM(widget, MPW_SPECTATORS, MPW_LAST_COMPANY + 1)) return;
+		PlayerID PId;
+		char move_rcon_command[20];
+		NetworkClientInfo *move_ci = DEREF_CLIENT_INFO(DEREF_CLIENT(_current_move_window_client));
+		if (widget == MPW_SPECTATORS) PId = PLAYER_SPECTATOR;
+		else {
+			PId = (PlayerID)(widget - 4);
+		}
+		if (PId == move_ci->client_playas) return;
+		if (IsValidPlayer(PId) && GetPlayer(PId)->is_active || PId == PLAYER_SPECTATOR) {
+			DEBUG(misc, 0, "widget: %d playerid: %d", widget, PId);
+			if (PId ==PLAYER_SPECTATOR) sprintf(move_rcon_command, "move %d", move_ci->client_index);
+			else sprintf(move_rcon_command, "move %d %d", move_ci->client_index, PId + 1);
+			if (_network_server) {
+				IConsoleCmdExec(move_rcon_command);
+			}
+			else {
+				NetworkClientSendRcon(_settings_client.network.rcon_password, move_rcon_command);
+			}
+		}
+		else return;
+		DeleteWindowById(WC_MOVE_PLAYER, 0);
+	}
+};
+
+static const Widget _move_player_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   249,     0,    13, STR_MOVE_PLAYER_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,   125, 0x0,                            STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    16,    27, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    28,    39, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    40,    51, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    52,    63, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    64,    75, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    76,    87, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    88,    99, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,   100,   111, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,   112,   123, 0x0,                            STR_MOVE_PLAYER_TOOLTIP},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _move_player_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 126, 250, 126,
+	WC_MOVE_PLAYER, WC_NONE,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_move_player_widgets,
+};
+
+static void ShowMovePlayerWindow()
+{
+	DeleteWindowById(WC_MOVE_PLAYER, 0);
+	AllocateWindowDescFront<MovePlayerWindow>(&_move_player_desc, 0);
+}
+
+enum MutePlayerWindowWidgets {
+	MUPW_CLOSE,
+	MUPW_CAPTION,
+	MUPW_BACKGROUND,
+	MUPW_BROADCAST,
+	MUPW_TEAM,
+	MUPW_CLIENT
+};
+
+struct MutePlayerWindow : Window {
+	MutePlayerWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+
+		NetworkClientInfo *mute_ci = DEREF_CLIENT_INFO(DEREF_CLIENT(_current_mute_window_client));
+		assert(mute_ci != NULL);
+		this->SetWidgetLoweredState(MUPW_BROADCAST, HasBit(mute_ci->mute, 1));
+		this->SetWidgetLoweredState(MUPW_TEAM, HasBit(mute_ci->mute, 2));
+		this->SetWidgetLoweredState(MUPW_CLIENT, HasBit(mute_ci->mute, 3));
+		this->DrawWidgets();
+		DrawString(21,17 + 0 * 12, STR_MUTE_PLAYER_ALL, TC_WHITE);
+		DrawString(21, 17 + 1 * 12, STR_MUTE_PLAYER_TEAM, TC_WHITE);
+		DrawString(21, 17 + 2 * 12, STR_MUTE_PLAYER_PRIVATE, TC_WHITE);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (!IsInsideMM(widget, MUPW_BROADCAST, MUPW_CLIENT + 1)) return;
+		NetworkClientInfo *mute_ci = DEREF_CLIENT_INFO(DEREF_CLIENT(_current_mute_window_client));
+		char mute_rcon_command[12];
+		byte clicked = widget - MUPW_BROADCAST + 1;
+		sprintf(mute_rcon_command, "mute %d %d", mute_ci->client_index, clicked);
+		if (_network_server) {
+			IConsoleCmdExec(mute_rcon_command);
+		}
+		else if (_networking && _settings_client.network.rcon_password[0] != '\0'){
+			NetworkClientSendRcon(_settings_client.network.rcon_password, mute_rcon_command);
+		}
+	}
+};
+
+static const Widget _mute_player_widgets[] = {
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   249,     0,    13, STR_MUTE_PLAYER_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,   53, 0x0,                                            STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    16,    27, 0x0,                            STR_MUTE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    28,    39, 0x0,                            STR_MUTE_PLAYER_TOOLTIP},
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    40,    51, 0x0,                            STR_MUTE_PLAYER_TOOLTIP},
+{   WIDGETS_END},
+};
+
+static const WindowDesc _mute_player_desc = {
+	WDP_AUTO, WDP_AUTO, 250, 54, 250, 54,
+	WC_MUTE_PLAYER, WC_NONE,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	_mute_player_widgets,
+};
+
+static void ShowMutePlayerWindow()
+{
+	DeleteWindowById(WC_MUTE_PLAYER, 0);
+	AllocateWindowDescFront<MutePlayerWindow>(&_mute_player_desc, 0);
+}
+
 #endif /* ENABLE_NETWORK */
